move utils to zutils
This commit is contained in:
parent
a153eded7b
commit
959740af19
@ -7,7 +7,7 @@ import { reportPayResult } from 'service/game.svr'
|
||||
import { PriceSvr } from 'service/price.svr'
|
||||
import { OrderCacheSvr } from 'service/ordercache.svr'
|
||||
import { BaseController, role, ROLE_ANON, router, ZError } from 'zutils'
|
||||
import { fromWei, toBigWei } from 'utils/number.util'
|
||||
import { fromWei, toBigWei } from 'zutils/utils/bn.util'
|
||||
|
||||
let errorRes = function (msg: string) {
|
||||
logger.info(`error res: ${msg}`)
|
||||
|
@ -2,7 +2,7 @@ import { getModelForClass, index, modelOptions, mongoose, prop, ReturnModelType,
|
||||
import { dbconn } from 'decorators/dbconn'
|
||||
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
||||
import { BaseModule } from './Base'
|
||||
import { genRandomString, sha512 } from 'utils/security.util'
|
||||
import { genRandomString, sha512 } from 'zutils/utils/security.util'
|
||||
|
||||
export enum PlatEnum {
|
||||
GOOGLE = 0,
|
||||
|
@ -6,7 +6,7 @@ import { plugin, prop, ReturnModelType } from '@typegoose/typegoose'
|
||||
import findOrCreate from 'mongoose-findorcreate'
|
||||
import { Connection } from 'mongoose'
|
||||
import { ObjectId } from 'bson'
|
||||
import { isTrue } from '../utils/string.util'
|
||||
import { isTrue } from 'zutils/utils/string.util'
|
||||
import { AnyParamConstructor } from '@typegoose/typegoose/lib/types'
|
||||
|
||||
const jsonExcludeKeys = ['updatedAt', '__v']
|
||||
|
@ -1,37 +1,26 @@
|
||||
import {
|
||||
FastifyInstance,
|
||||
FastifyPluginAsync,
|
||||
FastifyReply,
|
||||
FastifyRequest,
|
||||
} from "fastify";
|
||||
import fastifyPlugin from "fastify-plugin";
|
||||
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify'
|
||||
import fastifyPlugin from 'fastify-plugin'
|
||||
|
||||
/**
|
||||
* 将post 和 get 的参数统一到 req.params
|
||||
*/
|
||||
declare module "fastify" {
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
zReqParser: (request: FastifyRequest, reply: FastifyReply) => {};
|
||||
zReqParser: (request: FastifyRequest, reply: FastifyReply) => {}
|
||||
}
|
||||
}
|
||||
const zReqParserPlugin: FastifyPluginAsync = async function (
|
||||
fastify: FastifyInstance,
|
||||
options?: any
|
||||
) {
|
||||
fastify.addHook(
|
||||
"preValidation",
|
||||
async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
let params = request.params || {};
|
||||
if (request.query) {
|
||||
Object.assign(params, request.query);
|
||||
}
|
||||
if (request.body) {
|
||||
Object.assign(params, request.body);
|
||||
}
|
||||
request.params = params;
|
||||
const zReqParserPlugin: FastifyPluginAsync = async function (fastify: FastifyInstance, options?: any) {
|
||||
fastify.addHook('preValidation', async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
let params = request.params || {}
|
||||
if (request.query) {
|
||||
Object.assign(params, request.query)
|
||||
}
|
||||
);
|
||||
return;
|
||||
};
|
||||
if (request.body) {
|
||||
Object.assign(params, request.body)
|
||||
}
|
||||
request.params = params
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
export default fastifyPlugin(zReqParserPlugin, "4.x");
|
||||
export default fastifyPlugin(zReqParserPlugin, '4.x')
|
||||
|
@ -1,73 +1,62 @@
|
||||
import {
|
||||
FastifyInstance,
|
||||
FastifyPluginAsync,
|
||||
FastifyReply,
|
||||
FastifyRequest,
|
||||
} from "fastify";
|
||||
import fastifyPlugin from "fastify-plugin";
|
||||
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify'
|
||||
import fastifyPlugin from 'fastify-plugin'
|
||||
|
||||
const getTokenFromHeader = function (request) {
|
||||
let token: string | undefined;
|
||||
let token: string | undefined
|
||||
if (request.headers && request.headers.authorization) {
|
||||
const parts = request.headers.authorization.split(" ");
|
||||
const parts = request.headers.authorization.split(' ')
|
||||
if (parts.length === 2) {
|
||||
const scheme = parts[0];
|
||||
const scheme = parts[0]
|
||||
if (/^Bearer$/i.test(scheme)) {
|
||||
token = parts[1];
|
||||
token = parts[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return token;
|
||||
};
|
||||
return token
|
||||
}
|
||||
const getTokenFromCookie = function (request) {
|
||||
let token: string | undefined;
|
||||
let token: string | undefined
|
||||
if (request.cookies) {
|
||||
if (request.cookies["token"]) {
|
||||
token = request.cookies["token"];
|
||||
if (request.cookies['token']) {
|
||||
token = request.cookies['token']
|
||||
}
|
||||
}
|
||||
return token;
|
||||
};
|
||||
return token
|
||||
}
|
||||
|
||||
const getTokenFromParams = function (request) {
|
||||
let token: string | undefined;
|
||||
token = request.params && request.params.token;
|
||||
return token;
|
||||
};
|
||||
let token: string | undefined
|
||||
token = request.params && request.params.token
|
||||
return token
|
||||
}
|
||||
|
||||
const getTokenFromQuery = function (request) {
|
||||
let token: string | undefined;
|
||||
token = request.query && request.query.token;
|
||||
return token;
|
||||
};
|
||||
let token: string | undefined
|
||||
token = request.query && request.query.token
|
||||
return token
|
||||
}
|
||||
|
||||
const getTokenFromBody = function (request) {
|
||||
let token: string | undefined;
|
||||
token = request.body && request.body.token;
|
||||
return token;
|
||||
};
|
||||
let token: string | undefined
|
||||
token = request.body && request.body.token
|
||||
return token
|
||||
}
|
||||
|
||||
const zTokenParserPlugin: FastifyPluginAsync = async function (
|
||||
fastify: FastifyInstance,
|
||||
options?: any
|
||||
) {
|
||||
fastify.addHook(
|
||||
"preValidation",
|
||||
async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
request["token"] =
|
||||
getTokenFromHeader(request) ||
|
||||
getTokenFromCookie(request) ||
|
||||
getTokenFromParams(request) ||
|
||||
getTokenFromQuery(request) ||
|
||||
getTokenFromBody(request);
|
||||
}
|
||||
);
|
||||
return;
|
||||
};
|
||||
const zTokenParserPlugin: FastifyPluginAsync = async function (fastify: FastifyInstance, options?: any) {
|
||||
fastify.addHook('preValidation', async (request: FastifyRequest, reply: FastifyReply) => {
|
||||
request['token'] =
|
||||
getTokenFromHeader(request) ||
|
||||
getTokenFromCookie(request) ||
|
||||
getTokenFromParams(request) ||
|
||||
getTokenFromQuery(request) ||
|
||||
getTokenFromBody(request)
|
||||
})
|
||||
return
|
||||
}
|
||||
/**
|
||||
* 依次从request的header, cookie, params, query和body中获取token, 加入到request.token中
|
||||
* header中的字段key为authorization, 格式为 Bearer xxxx
|
||||
* 其他位置的key都为 token
|
||||
*/
|
||||
|
||||
export default fastifyPlugin(zTokenParserPlugin, "4.x");
|
||||
export default fastifyPlugin(zTokenParserPlugin, '4.x')
|
||||
|
@ -1,19 +1,19 @@
|
||||
import {NetClient} from "net/NetClient";
|
||||
import { NetClient } from 'net/NetClient'
|
||||
|
||||
const FACEBOOK_API_HOST = 'https://graph.facebook.com'
|
||||
export const FACEBOOK_APP_ID = '1204701000119770';
|
||||
const FACEBOOK_APP_SECRET = '5a1deba64b30c7326f497fc52691207f';
|
||||
export const FACEBOOK_APP_ID = '1204701000119770'
|
||||
const FACEBOOK_APP_SECRET = '5a1deba64b30c7326f497fc52691207f'
|
||||
|
||||
export async function getAppAccessToken() {
|
||||
const url = `${FACEBOOK_API_HOST}/oauth/access_token?client_id=${FACEBOOK_APP_ID}&clent_secret=${FACEBOOK_APP_SECRET}&grant_type=client_credentials`;
|
||||
return new NetClient().httpGet(url);
|
||||
}
|
||||
export async function verifyFbUserAccessToken(accessToken: string){
|
||||
const url = `${FACEBOOK_API_HOST}/debug_token?input_token=${accessToken}&access_token=GG|${FACEBOOK_APP_ID}|${FACEBOOK_APP_SECRET}`;
|
||||
return new NetClient().httpGet(url);
|
||||
const url = `${FACEBOOK_API_HOST}/oauth/access_token?client_id=${FACEBOOK_APP_ID}&clent_secret=${FACEBOOK_APP_SECRET}&grant_type=client_credentials`
|
||||
return new NetClient().httpGet(url)
|
||||
}
|
||||
export async function verifyFbUserAccessToken(accessToken: string) {
|
||||
const url = `${FACEBOOK_API_HOST}/debug_token?input_token=${accessToken}&access_token=GG|${FACEBOOK_APP_ID}|${FACEBOOK_APP_SECRET}`
|
||||
return new NetClient().httpGet(url)
|
||||
}
|
||||
|
||||
export async function fetchUserInfo(accessToken: string) {
|
||||
const url = `${FACEBOOK_API_HOST}/me?fields=["email","id", "name"]&access_token=${accessToken}`;
|
||||
return new NetClient().httpGet(url);
|
||||
const url = `${FACEBOOK_API_HOST}/me?fields=["email","id", "name"]&access_token=${accessToken}`
|
||||
return new NetClient().httpGet(url)
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import axios from 'axios'
|
||||
import { hmacsha256, md5, sha1 } from 'utils/security.util'
|
||||
import { hmacSha256, md5, sha1 } from 'zutils/utils/security.util'
|
||||
import crypto from 'crypto'
|
||||
import { generateKVStr } from 'utils/net.util'
|
||||
import { generateKVStr } from 'zutils/utils/net.util'
|
||||
import logger from 'logger/logger'
|
||||
import { GasSvr } from './gas.svr'
|
||||
import { toBigInt, toBigWei } from 'utils/number.util'
|
||||
import { toBigInt, toBigWei } from 'zutils/utils/bn.util'
|
||||
import { PriceSvr } from './price.svr'
|
||||
|
||||
export function createSimpleSign(data: any) {
|
||||
@ -17,7 +17,7 @@ export function createSimpleSign(data: any) {
|
||||
.sort()
|
||||
.map(key => `${key}=${signData[key]}`)
|
||||
.join('&')
|
||||
let sign = hmacsha256(signStr, secret)
|
||||
let sign = hmacSha256(signStr, secret).toLowerCase()
|
||||
return {
|
||||
appid,
|
||||
timestamp,
|
||||
@ -85,7 +85,7 @@ export function checkSimpleSign(headers: any, data: any) {
|
||||
.sort()
|
||||
.map(key => `${key}=${signData[key]}`)
|
||||
.join('&')
|
||||
const expectedSign = hmacsha256(signStr, process.env.ALCHEMY_APP_SECRET)
|
||||
const expectedSign = hmacSha256(signStr, process.env.ALCHEMY_APP_SECRET).toLowerCase()
|
||||
logger.info('compare sign: ', sign, expectedSign)
|
||||
// const expectedSign = sha1(appIdToCheck + process.env.ALCHEMY_APP_SECRET + timestamp)
|
||||
return sign === expectedSign
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { shortUuid, uuid } from 'utils/security.util'
|
||||
import { shortUuid } from 'zutils/utils/security.util'
|
||||
import { ZError, singleton } from 'zutils'
|
||||
|
||||
export interface IQrData {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import axios from 'axios'
|
||||
import { PayRecordClass } from 'modules/PayRecord'
|
||||
import { DocumentType } from '@typegoose/typegoose'
|
||||
import { hmacsha256 } from 'utils/security.util'
|
||||
import { hmacSha256 } from 'zutils/utils/security.util'
|
||||
import { NetClient } from 'net/NetClient'
|
||||
import logger from 'logger/logger'
|
||||
import { ReportQueue } from 'modules/ReportQueue'
|
||||
@ -47,7 +47,7 @@ export function assembleGameData(data: DocumentType<PayRecordClass>, mini = true
|
||||
|
||||
export function checkGameSign({ id, timestamp, sign }: { id: string; timestamp: string; sign: string }) {
|
||||
const signStr = `id=${id}×tamp=${timestamp}`
|
||||
const hash = hmacsha256(signStr, process.env.HASH_SALT)
|
||||
const hash = hmacSha256(signStr, process.env.HASH_SALT).toLowerCase()
|
||||
return sign === hash
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ export async function reportPayResult(data: DocumentType<PayRecordClass>) {
|
||||
.sort()
|
||||
.map(key => `${key}=${encodeURIComponent(repData[key])}`)
|
||||
.join('&')
|
||||
const sign = hmacsha256(signStr, process.env.HASH_SALT)
|
||||
const sign = hmacSha256(signStr, process.env.HASH_SALT).toLowerCase()
|
||||
const url = `${process.env.GAME_PAY_CB_URL}?c=Shop&a=buyGoodsDirect&${signStr}&sign=${sign}`
|
||||
const reqConfig: any = {
|
||||
method: 'get',
|
||||
@ -92,7 +92,7 @@ export async function reportPurchaseResult(records: IPayResult[], channel: strin
|
||||
.join('&'),
|
||||
)
|
||||
.join('&')
|
||||
const sign = hmacsha256(signStr, process.env.HASH_SALT)
|
||||
const sign = hmacSha256(signStr, process.env.HASH_SALT).toLowerCase()
|
||||
reportData.sign = sign
|
||||
const reqData = {
|
||||
url,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import axios from 'axios'
|
||||
import { HTTP_GET, HTTP_POST } from 'common/Constants'
|
||||
import logger from 'logger/logger'
|
||||
import { generateKVStr } from 'utils/net.util'
|
||||
import { generateKVStr } from 'zutils/utils/net.util'
|
||||
import { prepareOkxReqCfg } from 'utils/okx.utils'
|
||||
|
||||
const OKX_BASE = 'https://www.okx.com/api/v5/mktplace'
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { GasSvr } from 'service/gas.svr'
|
||||
import { PriceSvr } from 'service/price.svr'
|
||||
import { fromWei, toBigInt, toBigWei } from 'utils/number.util'
|
||||
import { fromWei, toBigInt, toBigWei } from 'zutils/utils/bn.util'
|
||||
|
||||
async function main() {
|
||||
let cryptoPrice = '0.1'
|
||||
|
@ -1,182 +0,0 @@
|
||||
const TIMEOUT_ERROR = new Error('timeout')
|
||||
|
||||
const hexRe = /^[0-9A-Fa-f]+$/gu
|
||||
|
||||
/**
|
||||
* Execute fetch and verify that the response was successful.
|
||||
*
|
||||
* @param request - Request information.
|
||||
* @param options - Fetch options.
|
||||
* @returns The fetch response.
|
||||
*/
|
||||
export async function successfulFetch(request: string, options?: RequestInit) {
|
||||
const response = await fetch(request, options)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Fetch failed with status '${response.status}' for request '${request}'`)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute fetch and return object response.
|
||||
*
|
||||
* @param request - The request information.
|
||||
* @param options - The fetch options.
|
||||
* @returns The fetch response JSON data.
|
||||
*/
|
||||
export async function handleFetch(request: string, options?: RequestInit) {
|
||||
const response = await successfulFetch(request, options)
|
||||
const object = await response.json()
|
||||
return object
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute fetch and return object response, log if known error thrown, otherwise rethrow error.
|
||||
*
|
||||
* @param request - the request options object
|
||||
* @param request.url - The request url to query.
|
||||
* @param request.options - The fetch options.
|
||||
* @param request.timeout - Timeout to fail request
|
||||
* @param request.errorCodesToCatch - array of error codes for errors we want to catch in a particular context
|
||||
* @returns The fetch response JSON data or undefined (if error occurs).
|
||||
*/
|
||||
export async function fetchWithErrorHandling({
|
||||
url,
|
||||
options,
|
||||
timeout,
|
||||
errorCodesToCatch,
|
||||
}: {
|
||||
url: string
|
||||
options?: RequestInit
|
||||
timeout?: number
|
||||
errorCodesToCatch?: number[]
|
||||
}) {
|
||||
let result
|
||||
try {
|
||||
if (timeout) {
|
||||
result = Promise.race([
|
||||
await handleFetch(url, options),
|
||||
new Promise<Response>((_, reject) =>
|
||||
setTimeout(() => {
|
||||
reject(TIMEOUT_ERROR)
|
||||
}, timeout),
|
||||
),
|
||||
])
|
||||
} else {
|
||||
result = await handleFetch(url, options)
|
||||
}
|
||||
} catch (e) {
|
||||
logOrRethrowError(e, errorCodesToCatch)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch that fails after timeout.
|
||||
*
|
||||
* @param url - Url to fetch.
|
||||
* @param options - Options to send with the request.
|
||||
* @param timeout - Timeout to fail request.
|
||||
* @returns Promise resolving the request.
|
||||
*/
|
||||
export async function timeoutFetch(url: string, options?: RequestInit, timeout = 500): Promise<Response> {
|
||||
return Promise.race([
|
||||
successfulFetch(url, options),
|
||||
new Promise<Response>((_, reject) =>
|
||||
setTimeout(() => {
|
||||
reject(TIMEOUT_ERROR)
|
||||
}, timeout),
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to log if error is a common fetch error and otherwise rethrow it.
|
||||
*
|
||||
* @param error - Caught error that we should either rethrow or log to console
|
||||
* @param codesToCatch - array of error codes for errors we want to catch and log in a particular context
|
||||
*/
|
||||
function logOrRethrowError(error: any, codesToCatch: number[] = []) {
|
||||
if (!error) {
|
||||
return
|
||||
}
|
||||
|
||||
const includesErrorCodeToCatch = codesToCatch.some(code =>
|
||||
error.message.includes(`Fetch failed with status '${code}'`),
|
||||
)
|
||||
|
||||
if (
|
||||
error instanceof Error &&
|
||||
(includesErrorCodeToCatch || error.message.includes('Failed to fetch') || error === TIMEOUT_ERROR)
|
||||
) {
|
||||
console.error(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 key1=val1&key2=val2的字符串
|
||||
* @param {object} data 需要处理的对象
|
||||
* @param {boolean} sort 是否按key生序重排
|
||||
* @param {boolean} ignoreNull 是否过滤空值(空格或者null值不参与拼接)
|
||||
* @param splitChar 连接的字符, 默认是&
|
||||
* @param equalChar =
|
||||
*/
|
||||
export function generateKVStr({
|
||||
data = {},
|
||||
sort = false,
|
||||
encode = false,
|
||||
ignoreNull = true,
|
||||
splitChar = '&',
|
||||
equalChar = '=',
|
||||
uri = '',
|
||||
}: {
|
||||
data?: any
|
||||
sort?: boolean
|
||||
encode?: boolean
|
||||
ignoreNull?: boolean
|
||||
splitChar?: string
|
||||
equalChar?: string
|
||||
uri?: string
|
||||
}) {
|
||||
const keys = Object.keys(data)
|
||||
sort && keys.sort()
|
||||
let result = ''
|
||||
let i = 0
|
||||
for (let key of keys) {
|
||||
if (ignoreNull && !data[key]) {
|
||||
continue
|
||||
}
|
||||
if (i++ > 0) result += splitChar
|
||||
if (encode) {
|
||||
result += `${key}${equalChar}${encodeURIComponent(data[key])}`
|
||||
} else {
|
||||
result += `${key}${equalChar}${data[key]}`
|
||||
}
|
||||
}
|
||||
if (uri) {
|
||||
const joinChar = uri.search(/\?/) === -1 ? '?' : '&'
|
||||
result = uri + joinChar + result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 将key1=val&key2=val的字符串组装成对象
|
||||
* @param str key1=val&key2=val的字符串
|
||||
* @param splitChar 连接的字符, 默认是&
|
||||
* @param equalChar =
|
||||
*/
|
||||
export function keyValToObject(str: string, splitChar: string = '&', equalChar = '='): {} {
|
||||
let result: any = {}
|
||||
if (!str) {
|
||||
return result
|
||||
}
|
||||
let arrs = str.split(splitChar)
|
||||
for (let sub of arrs) {
|
||||
let subArr = sub.split(equalChar)
|
||||
result[subArr[0]] = subArr[1]
|
||||
}
|
||||
return result
|
||||
}
|
@ -1,218 +0,0 @@
|
||||
export declare type HexString = string
|
||||
export declare type Numbers = number | bigint | string | HexString
|
||||
|
||||
const isHexStrict = hex => typeof hex === 'string' && /^((-)?0x[0-9a-f]+|(0x))$/i.test(hex)
|
||||
export declare type ValidInputTypes = Uint8Array | bigint | string | number | boolean
|
||||
export const isHex = (hex: ValidInputTypes): boolean =>
|
||||
typeof hex === 'number' ||
|
||||
typeof hex === 'bigint' ||
|
||||
(typeof hex === 'string' && /^((-0x|0x|-)?[0-9a-f]+|(0x))$/i.test(hex))
|
||||
const base = BigInt(10)
|
||||
const expo10 = (expo: number) => base ** BigInt(expo)
|
||||
|
||||
export const ethUnitMap = {
|
||||
noether: BigInt('0'),
|
||||
wei: BigInt(1),
|
||||
kwei: expo10(3),
|
||||
Kwei: expo10(3),
|
||||
babbage: expo10(3),
|
||||
femtoether: expo10(3),
|
||||
mwei: expo10(6),
|
||||
Mwei: expo10(6),
|
||||
lovelace: expo10(6),
|
||||
picoether: expo10(6),
|
||||
gwei: expo10(9),
|
||||
Gwei: expo10(9),
|
||||
shannon: expo10(9),
|
||||
nanoether: expo10(9),
|
||||
nano: expo10(9),
|
||||
szabo: expo10(12),
|
||||
microether: expo10(12),
|
||||
micro: expo10(12),
|
||||
finney: expo10(15),
|
||||
milliether: expo10(15),
|
||||
milli: expo10(15),
|
||||
ether: expo10(18),
|
||||
kether: expo10(21),
|
||||
grand: expo10(21),
|
||||
mether: expo10(24),
|
||||
gether: expo10(27),
|
||||
tether: expo10(30),
|
||||
}
|
||||
|
||||
export type EtherUnits = keyof typeof ethUnitMap
|
||||
|
||||
/**
|
||||
* Converts value to it's number representation
|
||||
*/
|
||||
export const hexToNumber = (value: string): bigint | number => {
|
||||
if (!isHexStrict(value)) {
|
||||
throw new Error('Invalid hex string')
|
||||
}
|
||||
|
||||
const [negative, hexValue] = value.startsWith('-') ? [true, value.slice(1)] : [false, value]
|
||||
const num = BigInt(hexValue)
|
||||
|
||||
if (num > Number.MAX_SAFE_INTEGER) {
|
||||
return negative ? -num : num
|
||||
}
|
||||
|
||||
if (num < Number.MIN_SAFE_INTEGER) {
|
||||
return num
|
||||
}
|
||||
|
||||
return negative ? -1 * Number(num) : Number(num)
|
||||
}
|
||||
|
||||
export const toNumber = (value: Numbers): number | bigint => {
|
||||
if (typeof value === 'number') {
|
||||
return value
|
||||
}
|
||||
|
||||
if (typeof value === 'bigint') {
|
||||
return value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER ? Number(value) : value
|
||||
}
|
||||
|
||||
if (typeof value === 'string' && isHexStrict(value)) {
|
||||
return hexToNumber(value)
|
||||
}
|
||||
|
||||
try {
|
||||
return toNumber(BigInt(value))
|
||||
} catch {
|
||||
throw new Error('ivalid number: ' + value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto converts any given value into it's bigint representation
|
||||
*
|
||||
* @param value - The value to convert
|
||||
* @returns - Returns the value in bigint representation
|
||||
|
||||
* @example
|
||||
* ```ts
|
||||
* console.log(web3.utils.toBigInt(1));
|
||||
* > 1n
|
||||
* ```
|
||||
*/
|
||||
export const toBigInt = (value: unknown): bigint => {
|
||||
if (typeof value === 'number') {
|
||||
return BigInt(value)
|
||||
}
|
||||
|
||||
if (typeof value === 'bigint') {
|
||||
return value
|
||||
}
|
||||
|
||||
// isHex passes for dec, too
|
||||
if (typeof value === 'string' && isHex(value)) {
|
||||
return BigInt(value)
|
||||
}
|
||||
|
||||
if (typeof value === 'string' && value.indexOf(',') >= 0) {
|
||||
return BigInt(value.replace(/,/g, ''))
|
||||
}
|
||||
|
||||
throw new Error('invalid number' + value)
|
||||
}
|
||||
|
||||
export const toBigWei = (number: Numbers, unit: EtherUnits = 'ether'): bigint => {
|
||||
return toBigInt(toWei(number, unit))
|
||||
}
|
||||
|
||||
export const toWei = (number: Numbers, unit: EtherUnits = 'ether'): string => {
|
||||
const denomination = ethUnitMap[unit]
|
||||
|
||||
if (!denomination) {
|
||||
throw new Error('error unit: ' + unit)
|
||||
}
|
||||
|
||||
// if value is decimal e.g. 24.56 extract `integer` and `fraction` part
|
||||
// to avoid `fraction` to be null use `concat` with empty string
|
||||
typeof number === 'string' && number.indexOf(',') >= 0 && (number = number.replace(/,/g, ''))
|
||||
const [integer, fraction] = String(typeof number === 'string' && !isHexStrict(number) ? number : toNumber(number))
|
||||
.split('.')
|
||||
.concat('')
|
||||
|
||||
// join the value removing `.` from
|
||||
// 24.56 -> 2456
|
||||
const value = BigInt(`${integer}${fraction}`)
|
||||
|
||||
// multiply value with denomination
|
||||
// 2456 * 1000000 -> 2456000000
|
||||
const updatedValue = value * denomination
|
||||
|
||||
// count number of zeros in denomination
|
||||
const numberOfZerosInDenomination = denomination.toString().length - 1
|
||||
|
||||
// check which either `fraction` or `denomination` have lower number of zeros
|
||||
const decimals = Math.min(fraction.length, numberOfZerosInDenomination)
|
||||
|
||||
if (decimals === 0) {
|
||||
return updatedValue.toString()
|
||||
}
|
||||
|
||||
// Add zeros to make length equal to required decimal points
|
||||
// If string is larger than decimal points required then remove last zeros
|
||||
return updatedValue.toString().padStart(decimals, '0').slice(0, -decimals)
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a number of wei and converts it to any other ether unit.
|
||||
* @param number - The value in wei
|
||||
* @param unit - The unit to convert to
|
||||
* @returns - Returns the converted value in the given unit
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* console.log(web3.utils.fromWei("1", "ether"));
|
||||
* > 0.000000000000000001
|
||||
*
|
||||
* console.log(web3.utils.fromWei("1", "shannon"));
|
||||
* > 0.000000001
|
||||
* ```
|
||||
*/
|
||||
export const fromWei = (number: Numbers, unit: EtherUnits = 'ether'): string => {
|
||||
const denomination = ethUnitMap[unit]
|
||||
|
||||
if (!denomination) {
|
||||
throw new Error('invalid unit: ' + unit)
|
||||
}
|
||||
|
||||
// value in wei would always be integer
|
||||
// 13456789, 1234
|
||||
const value = String(toNumber(number))
|
||||
|
||||
// count number of zeros in denomination
|
||||
// 1000000 -> 6
|
||||
const numberOfZerosInDenomination = denomination.toString().length - 1
|
||||
|
||||
if (numberOfZerosInDenomination <= 0) {
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
// pad the value with required zeros
|
||||
// 13456789 -> 13456789, 1234 -> 001234
|
||||
const zeroPaddedValue = value.padStart(numberOfZerosInDenomination, '0')
|
||||
|
||||
// get the integer part of value by counting number of zeros from start
|
||||
// 13456789 -> '13'
|
||||
// 001234 -> ''
|
||||
const integer = zeroPaddedValue.slice(0, -numberOfZerosInDenomination)
|
||||
|
||||
// get the fraction part of value by counting number of zeros backward
|
||||
// 13456789 -> '456789'
|
||||
// 001234 -> '001234'
|
||||
const fraction = zeroPaddedValue.slice(-numberOfZerosInDenomination).replace(/\.?0+$/, '')
|
||||
|
||||
if (integer === '') {
|
||||
return `0.${fraction}`
|
||||
}
|
||||
|
||||
if (fraction === '') {
|
||||
return integer
|
||||
}
|
||||
|
||||
return `${integer}.${fraction}`
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @param {Function} cb
|
||||
* @param {number} maxRetries
|
||||
* @param {any[]} errorWhiteList
|
||||
* @param {number} retries
|
||||
* @return {Promise<T>}
|
||||
*/
|
||||
export function retry<T = any>(cb: Function, maxRetries: number = 3, errorWhiteList: any[] = [], retries: number = 0) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
cb()
|
||||
.then(resolve)
|
||||
.catch(e => {
|
||||
if (errorWhiteList.indexOf(e.constructor) !== -1 && retries++ < maxRetries) {
|
||||
setTimeout(() => {
|
||||
retry<T>(cb, maxRetries, errorWhiteList, retries)
|
||||
.then(resolve)
|
||||
.catch(e2 => reject(e2))
|
||||
}, Math.floor(Math.random() * Math.pow(2, retries) * 400))
|
||||
} else {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export class Deferred<T = any> {
|
||||
public promise: Promise<T>
|
||||
|
||||
public resolve: Function
|
||||
public reject: Function
|
||||
|
||||
constructor() {
|
||||
this.promise = new Promise<T>((resolve, reject) => {
|
||||
this.resolve = resolve
|
||||
this.reject = reject
|
||||
})
|
||||
}
|
||||
|
||||
public then(func: (value: T) => any) {
|
||||
return this.promise.then.apply(this.promise, arguments)
|
||||
}
|
||||
|
||||
public catch(func: (value: any) => any) {
|
||||
return this.promise.catch(func)
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
import crypto from 'crypto'
|
||||
import { compressUuid } from './string.util'
|
||||
const ENCODER = 'base64'
|
||||
const REG_KEY = /^[0-9a-fA-F]{63,64}$/
|
||||
|
||||
export function isEncrypt(msg: string) {
|
||||
return !REG_KEY.test(msg)
|
||||
}
|
||||
|
||||
export function aesEncrypt(text: string, password: string, iv: string) {
|
||||
var md5 = crypto.createHash('md5')
|
||||
const key = md5.update(password).digest('hex')
|
||||
let cipher = crypto.createCipheriv('aes-256-cbc', key, iv)
|
||||
let encrypted = cipher.update(text, 'utf8', ENCODER)
|
||||
encrypted += cipher.final(ENCODER)
|
||||
return encrypted
|
||||
}
|
||||
|
||||
export function aesDecrypt(encryptedText: string, password: string, iv: string) {
|
||||
var md5 = crypto.createHash('md5')
|
||||
const key = md5.update(password).digest('hex')
|
||||
let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv)
|
||||
let decrypted = decipher.update(encryptedText, ENCODER, 'utf8')
|
||||
return decrypted + decipher.final('utf8')
|
||||
}
|
||||
|
||||
export function hmacsha256(text: string, secret: string) {
|
||||
const mac = crypto.createHmac('sha256', secret)
|
||||
const data = mac.update(text).digest('hex').toLowerCase()
|
||||
console.log(`HmacSHA256 rawContent is [${text}], key is [${secret}], hash result is [${data}]`)
|
||||
return data
|
||||
}
|
||||
|
||||
export function sha512(password: string, salt: string) {
|
||||
let hash = crypto.createHmac('sha512', salt)
|
||||
hash.update(password)
|
||||
let value = hash.digest('hex')
|
||||
return {
|
||||
salt: salt,
|
||||
passwordHash: value,
|
||||
}
|
||||
}
|
||||
|
||||
export function sha3_256(str: string) {
|
||||
let hash = crypto.createHash('sha3-256')
|
||||
hash.update(str)
|
||||
return hash.digest('hex')
|
||||
}
|
||||
|
||||
export function genRandomString(length: number) {
|
||||
return crypto
|
||||
.randomBytes(Math.ceil(length / 2))
|
||||
.toString('hex')
|
||||
.slice(0, length)
|
||||
}
|
||||
|
||||
export function uuid() {
|
||||
return crypto.randomUUID()
|
||||
}
|
||||
|
||||
export function shortUuid() {
|
||||
let uid = uuid()
|
||||
return compressUuid(uid)
|
||||
}
|
||||
|
||||
export function md5(content: string) {
|
||||
var md5 = crypto.createHash('md5')
|
||||
return md5.update(content).digest('hex')
|
||||
}
|
||||
|
||||
export function sha1(content: string) {
|
||||
var md5 = crypto.createHash('sha1')
|
||||
return md5.update(content).digest('hex')
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
/**
|
||||
* 根据key升序生成 key1=val1&key2=val2的字符串
|
||||
* @param {object} data 需要处理的对象
|
||||
* @param {boolean} ignoreNull 是否过滤空值(空格或者null值不参与拼接)
|
||||
* @param splitChar 连接的字符, 默认是&
|
||||
* @param equalChar =
|
||||
*/
|
||||
export function generateKeyValStr(data: Record<string, any>, ignoreNull = true, splitChar = '&', equalChar = '=') {
|
||||
const keys = Object.keys(data)
|
||||
keys.sort()
|
||||
let result = ''
|
||||
let i = 0
|
||||
for (let key of keys) {
|
||||
if (ignoreNull && !data[key]) {
|
||||
return
|
||||
}
|
||||
if (i++ > 0) result += splitChar
|
||||
result += `${key}${equalChar}${data[key]}`
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 将key1=val&key2=val的字符串组装成对象
|
||||
* @param str key1=val&key2=val的字符串
|
||||
* @param splitChar 连接的字符, 默认是&
|
||||
* @param equalChar =
|
||||
*/
|
||||
export function keyValToObject(str: string, splitChar: string = '&', equalChar = '='): {} {
|
||||
let result = {}
|
||||
if (!str) {
|
||||
return result
|
||||
}
|
||||
let arrs = str.split(splitChar)
|
||||
for (let sub of arrs) {
|
||||
let subArr = sub.split(equalChar)
|
||||
result[subArr[0]] = subArr[1]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断传入的值是否为true
|
||||
* @param {Object} obj 传入值为'true','TRUE',1,'1','on','ON','YES','yes'时,返回true,其他值均返回false
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isTrue(obj) {
|
||||
return (
|
||||
obj === 'true' ||
|
||||
obj === 'TRUE' ||
|
||||
obj === 'True' ||
|
||||
obj === 'on' ||
|
||||
obj === 'ON' ||
|
||||
obj === true ||
|
||||
obj === 1 ||
|
||||
obj === '1' ||
|
||||
obj === 'YES' ||
|
||||
obj === 'yes'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证ObjectId格式是否正确
|
||||
* @param {string} id
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isObjectId(id: string): boolean {
|
||||
//mongoose.Types.ObjectId.isValid(id)
|
||||
return /^[a-fA-F0-9]{24}$/.test(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 10进制 -> 62进制
|
||||
* @param {string | number} number
|
||||
* @return {string}
|
||||
*/
|
||||
export function string10to62(number: string | number) {
|
||||
const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'.split('')
|
||||
const radix = chars.length
|
||||
let qutient = +number
|
||||
const arr = []
|
||||
do {
|
||||
const mod = qutient % radix
|
||||
qutient = (qutient - mod) / radix
|
||||
arr.unshift(chars[mod])
|
||||
} while (qutient)
|
||||
return arr.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 62进制 -> 10 进制
|
||||
* @param {string} numberCode
|
||||
* @return {number}
|
||||
*/
|
||||
export function string62to10(numberCode: string) {
|
||||
const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'
|
||||
const radix = chars.length
|
||||
numberCode = numberCode + ''
|
||||
const len = numberCode.length
|
||||
let i = 0
|
||||
let originNumber = 0
|
||||
while (i < len) {
|
||||
originNumber += Math.pow(radix, i++) * (chars.indexOf(numberCode.charAt(len - i)) || 0)
|
||||
}
|
||||
return originNumber
|
||||
}
|
||||
|
||||
const reNormalUUID = /^[0-9a-fA-F-]{36}$/
|
||||
const reLongUUID = /^[0-9a-fA-F]{32}$/
|
||||
const reShortUUID = /^[0-9a-zA-Z+/]{22,23}$/
|
||||
const n = /-/g
|
||||
|
||||
export function compressUuid(e: string, t: boolean = false) {
|
||||
if (reNormalUUID.test(e)) {
|
||||
e = e.replace(n, '')
|
||||
} else if (!reLongUUID.test(e)) {
|
||||
return e
|
||||
}
|
||||
var r = !0 === t ? 2 : 5
|
||||
return compressHex(e, r)
|
||||
}
|
||||
|
||||
const CHARS_BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
export function compressHex(e: string, r: number) {
|
||||
var i,
|
||||
n = e.length
|
||||
i = void 0 !== r ? r : n % 3
|
||||
for (var s = e.slice(0, i), o = []; i < n; ) {
|
||||
var u = parseInt(e[i], 16),
|
||||
a = parseInt(e[i + 1], 16),
|
||||
c = parseInt(e[i + 2], 16)
|
||||
o.push(CHARS_BASE64[(u << 2) | (a >> 2)])
|
||||
o.push(CHARS_BASE64[((3 & a) << 4) | c])
|
||||
i += 3
|
||||
}
|
||||
return s + o.join('')
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user