Spaces:
Sleeping
Sleeping
| import os from 'os'; | |
| import path from 'path'; | |
| import crypto from 'crypto'; | |
| import { Readable, Writable } from 'stream'; | |
| import 'colors'; | |
| import mime from 'mime'; | |
| import fs from 'fs-extra'; | |
| import { v1 as uuid } from 'uuid'; | |
| import { format as dateFormat } from 'date-fns'; | |
| import CRC32 from 'crc-32'; | |
| import randomstring from 'randomstring'; | |
| import _ from 'lodash'; | |
| import { CronJob } from 'cron'; | |
| import HTTP_STATUS_CODE from './http-status-codes.ts'; | |
| const autoIdMap = new Map(); | |
| const util = { | |
| is2DArrays(value: any) { | |
| return _.isArray(value) && (!value[0] || (_.isArray(value[0]) && _.isArray(value[value.length - 1]))); | |
| }, | |
| uuid: (separator = true) => separator ? uuid() : uuid().replace(/\-/g, ""), | |
| autoId: (prefix = '') => { | |
| let index = autoIdMap.get(prefix); | |
| if(index > 999999) index = 0; //超过最大数字则重置为0 | |
| autoIdMap.set(prefix, (index || 0) + 1); | |
| return `${prefix}${index || 1}`; | |
| }, | |
| ignoreJSONParse(value: string) { | |
| const result = _.attempt(() => JSON.parse(value)); | |
| if(_.isError(result)) | |
| return null; | |
| return result; | |
| }, | |
| generateRandomString(options: any): string { | |
| return randomstring.generate(options); | |
| }, | |
| getResponseContentType(value: any): string | null { | |
| return value.headers ? (value.headers["content-type"] || value.headers["Content-Type"]) : null; | |
| }, | |
| generateCookie() { | |
| const timestamp = util.unixTimestamp(); | |
| const items = [ | |
| `Hm_lvt_4532beacc312859e0aa3e4a80566b706=${timestamp - Math.round(Math.random() * 2592000)}`, | |
| `Hm_lvt_358cae4815e85d48f7e8ab7f3680a74b=${timestamp - Math.round(Math.random() * 2592000)}`, | |
| `_ga=GA1.1.${util.generateRandomString({ length: 10, charset: 'numeric' })}.${timestamp - Math.round(Math.random() * 2592000)}`, | |
| `_ga_31QPQG2YYD=GS1.1.${timestamp - Math.round(Math.random() * 2592000)}.17.0.${timestamp - Math.round(Math.random() * 2592000)}.0.0.0`, | |
| `Hm_lpvt_4532beacc312859e0aa3e4a80566b706=${timestamp - Math.round(Math.random() * 2592000)}`, | |
| `Hm_lpvt_358cae4815e85d48f7e8ab7f3680a74b=${timestamp - Math.round(Math.random() * 2592000)}`, | |
| `_ga_YXD8W70SZP=GS1.1.${timestamp - Math.round(Math.random() * 2592000)}.35.1.${timestamp - Math.round(Math.random() * 2592000)}.0.0.0` | |
| ]; | |
| return items.join('; '); | |
| }, | |
| mimeToExtension(value: string) { | |
| let extension = mime.getExtension(value); | |
| if(extension == "mpga") | |
| return "mp3"; | |
| return extension; | |
| }, | |
| extractURLExtension(value: string) { | |
| const extname = path.extname(new URL(value).pathname); | |
| return extname.substring(1).toLowerCase(); | |
| }, | |
| createCronJob(cronPatterns: any, callback?: Function) { | |
| if(!_.isFunction(callback)) throw new Error("callback must be an Function"); | |
| return new CronJob(cronPatterns, () => callback(), null, false, "Asia/Shanghai"); | |
| }, | |
| getDateString(format = "yyyy-MM-dd", date = new Date()) { | |
| return dateFormat(date, format); | |
| }, | |
| getIPAddressesByIPv4(): string[] { | |
| const interfaces = os.networkInterfaces(); | |
| const addresses = []; | |
| for (let name in interfaces) { | |
| const networks = interfaces[name]; | |
| const results = networks.filter(network => network.family === "IPv4" && network.address !== "127.0.0.1" && !network.internal); | |
| if (results[0] && results[0].address) | |
| addresses.push(results[0].address); | |
| } | |
| return addresses; | |
| }, | |
| getMACAddressesByIPv4(): string[] { | |
| const interfaces = os.networkInterfaces(); | |
| const addresses = []; | |
| for (let name in interfaces) { | |
| const networks = interfaces[name]; | |
| const results = networks.filter(network => network.family === "IPv4" && network.address !== "127.0.0.1" && !network.internal); | |
| if (results[0] && results[0].mac) | |
| addresses.push(results[0].mac); | |
| } | |
| return addresses; | |
| }, | |
| generateSSEData(event?: string, data?: string, retry?: number) { | |
| return `event: ${event || "message"}\ndata: ${(data || "").replace(/\n/g, "\\n").replace(/\s/g, "\\s")}\nretry: ${retry || 3000}\n\n`; | |
| }, | |
| buildDataBASE64(type, ext, buffer) { | |
| return `data:${type}/${ext.replace("jpg", "jpeg")};base64,${buffer.toString("base64")}`; | |
| }, | |
| isLinux() { | |
| return os.platform() !== "win32"; | |
| }, | |
| isIPAddress(value) { | |
| return _.isString(value) && (/^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/.test(value) || /\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*/.test(value)); | |
| }, | |
| isPort(value) { | |
| return _.isNumber(value) && value > 0 && value < 65536; | |
| }, | |
| isReadStream(value): boolean { | |
| return value && (value instanceof Readable || "readable" in value || value.readable); | |
| }, | |
| isWriteStream(value): boolean { | |
| return value && (value instanceof Writable || "writable" in value || value.writable); | |
| }, | |
| isHttpStatusCode(value) { | |
| return _.isNumber(value) && Object.values(HTTP_STATUS_CODE).includes(value); | |
| }, | |
| isURL(value) { | |
| return !_.isUndefined(value) && /^(http|https)/.test(value); | |
| }, | |
| isSrc(value) { | |
| return !_.isUndefined(value) && /^\/.+\.[0-9a-zA-Z]+(\?.+)?$/.test(value); | |
| }, | |
| isBASE64(value) { | |
| return !_.isUndefined(value) && /^[a-zA-Z0-9\/\+]+(=?)+$/.test(value); | |
| }, | |
| isBASE64Data(value) { | |
| return /^data:/.test(value); | |
| }, | |
| extractBASE64DataFormat(value): string | null { | |
| const match = value.trim().match(/^data:(.+);base64,/); | |
| if(!match) return null; | |
| return match[1]; | |
| }, | |
| removeBASE64DataHeader(value): string { | |
| return value.replace(/^data:(.+);base64,/, ""); | |
| }, | |
| isDataString(value): boolean { | |
| return /^(base64|json):/.test(value); | |
| }, | |
| isStringNumber(value) { | |
| return _.isFinite(Number(value)); | |
| }, | |
| isUnixTimestamp(value) { | |
| return /^[0-9]{10}$/.test(`${value}`); | |
| }, | |
| isTimestamp(value) { | |
| return /^[0-9]{13}$/.test(`${value}`); | |
| }, | |
| isEmail(value) { | |
| return /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/.test(value); | |
| }, | |
| isAsyncFunction(value) { | |
| return Object.prototype.toString.call(value) === "[object AsyncFunction]"; | |
| }, | |
| async isAPNG(filePath) { | |
| let head; | |
| const readStream = fs.createReadStream(filePath, { start: 37, end: 40 }); | |
| const readPromise = new Promise((resolve, reject) => { | |
| readStream.once("end", resolve); | |
| readStream.once("error", reject); | |
| }); | |
| readStream.once("data", data => head = data); | |
| await readPromise; | |
| return head.compare(Buffer.from([0x61, 0x63, 0x54, 0x4c])) === 0; | |
| }, | |
| unixTimestamp() { | |
| return parseInt(`${Date.now() / 1000}`); | |
| }, | |
| timestamp() { | |
| return Date.now(); | |
| }, | |
| urlJoin(...values) { | |
| let url = ""; | |
| for (let i = 0; i < values.length; i++) | |
| url += `${i > 0 ? "/" : ""}${values[i].replace(/^\/*/, "").replace(/\/*$/, "")}`; | |
| return url; | |
| }, | |
| millisecondsToHmss(milliseconds) { | |
| if (_.isString(milliseconds)) return milliseconds; | |
| milliseconds = parseInt(milliseconds); | |
| const sec = Math.floor(milliseconds / 1000); | |
| const hours = Math.floor(sec / 3600); | |
| const minutes = Math.floor((sec - hours * 3600) / 60); | |
| const seconds = sec - hours * 3600 - minutes * 60; | |
| const ms = milliseconds % 60000 - seconds * 1000; | |
| return `${hours > 9 ? hours : "0" + hours}:${minutes > 9 ? minutes : "0" + minutes}:${seconds > 9 ? seconds : "0" + seconds}.${ms}`; | |
| }, | |
| millisecondsToTimeString(milliseconds) { | |
| if(milliseconds < 1000) | |
| return `${milliseconds}ms`; | |
| if(milliseconds < 60000) | |
| return `${parseFloat((milliseconds / 1000).toFixed(2))}s`; | |
| return `${Math.floor(milliseconds / 1000 / 60)}m${Math.floor(milliseconds / 1000 % 60)}s`; | |
| }, | |
| rgbToHex(r, g, b): string { | |
| return ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); | |
| }, | |
| hexToRgb(hex) { | |
| const value = parseInt(hex.replace(/^#/, ""), 16); | |
| return [(value >> 16) & 255, (value >> 8) & 255, value & 255]; | |
| }, | |
| md5(value) { | |
| return crypto.createHash("md5").update(value).digest("hex"); | |
| }, | |
| crc32(value) { | |
| return _.isBuffer(value) ? CRC32.buf(value) : CRC32.str(value); | |
| }, | |
| arrayParse(value): any[] { | |
| return _.isArray(value) ? value : [value]; | |
| }, | |
| booleanParse(value) { | |
| return value === "true" || value === true ? true : false | |
| }, | |
| encodeBASE64(value) { | |
| return Buffer.from(value).toString("base64"); | |
| }, | |
| decodeBASE64(value) { | |
| return Buffer.from(value, "base64").toString(); | |
| }, | |
| }; | |
| export default util; |