mirror of
https://github.com/LLM-Red-Team/qwen-free-api.git
synced 2025-04-19 06:09:14 +08:00
308 lines
8.8 KiB
TypeScript
308 lines
8.8 KiB
TypeScript
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";
|
|
import axios from "axios";
|
|
|
|
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;
|
|
},
|
|
|
|
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();
|
|
},
|
|
|
|
async fetchFileBASE64(url: string) {
|
|
const result = await axios.get(url, {
|
|
responseType: "arraybuffer",
|
|
});
|
|
return result.data.toString("base64");
|
|
},
|
|
};
|
|
|
|
export default util;
|