mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
utils: 提取公共模块
This commit is contained in:
1 parent
64fec8a407
commit
5cc63bcb22
16 files changed
+356
-427
No files matched your search
+1
-1
@@ -52,7 +52,7 @@ for (const package of packages) {
|
|||||||
if (package === 'ui-default') continue;
|
if (package === 'ui-default') continue;
|
||||||
const basedir = path.resolve(process.cwd(), 'packages', package);
|
const basedir = path.resolve(process.cwd(), 'packages', package);
|
||||||
const files = fs.readdirSync(basedir);
|
const files = fs.readdirSync(basedir);
|
||||||
if (!files.includes('src') && !files.map(n => n.split('.')[1]).includes('ts')) continue;
|
if (!files.includes('src') && !files.map(n => n.split('.')[1]).includes('ts') && package !== 'utils') continue;
|
||||||
if (package !== 'hydrooj') config.references.push({ path: `packages/${package}` });
|
if (package !== 'hydrooj') config.references.push({ path: `packages/${package}` });
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.resolve(basedir, 'tsconfig.json'),
|
path.resolve(basedir, 'tsconfig.json'),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/hydrojudge",
|
"name": "@hydrooj/hydrojudge",
|
||||||
"bin": "bin/hydrojudge.js",
|
"bin": "bin/hydrojudge.js",
|
||||||
"version": "2.4.17",
|
"version": "2.4.18",
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hydrooj/utils": "^1.0.0",
|
||||||
"adm-zip": "^0.5.5",
|
"adm-zip": "^0.5.5",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"bson": "^4.2.3",
|
"bson": "^4.2.3",
|
||||||
@@ -17,7 +18,6 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"p-queue": "^6.6.1",
|
"p-queue": "^6.6.1",
|
||||||
"shell-quote": "^1.7.2",
|
"shell-quote": "^1.7.2",
|
||||||
"systeminformation": "5.6.10",
|
|
||||||
"ws": "^7.4.4",
|
"ws": "^7.4.4",
|
||||||
"yargs": "^16.2.0"
|
"yargs": "^16.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,19 +14,6 @@ import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from '../status';
|
|||||||
import readCases from '../cases';
|
import readCases from '../cases';
|
||||||
import judge from '../judge';
|
import judge from '../judge';
|
||||||
|
|
||||||
function formatStr(content: string, ...args) {
|
|
||||||
let result = content;
|
|
||||||
if (args.length > 0) {
|
|
||||||
for (const key in args) {
|
|
||||||
if (args[key] !== undefined) {
|
|
||||||
const reg = new RegExp(`(\\{${key}\\})`, 'g');
|
|
||||||
result = result.replace(reg, args[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
class JudgeTask {
|
class JudgeTask {
|
||||||
stat: Record<string, Date>;
|
stat: Record<string, Date>;
|
||||||
session: any;
|
session: any;
|
||||||
@@ -131,14 +118,14 @@ class JudgeTask {
|
|||||||
delete data.message;
|
delete data.message;
|
||||||
}
|
}
|
||||||
if (data.judge_text && typeof data.judge_text !== 'string') {
|
if (data.judge_text && typeof data.judge_text !== 'string') {
|
||||||
data.judge_text = formatStr(data.judge_text.message, ...data.judge_text.params);
|
data.judge_text = data.judge_text.message.format(data.judge_text.params);
|
||||||
}
|
}
|
||||||
if (data.case?.message !== undefined) {
|
if (data.case?.message !== undefined) {
|
||||||
data.case.judge_text = data.case.message;
|
data.case.judge_text = data.case.message;
|
||||||
delete data.case.message;
|
delete data.case.message;
|
||||||
}
|
}
|
||||||
if (data.case?.judge_text && typeof data.case?.judge_text !== 'string') {
|
if (data.case?.judge_text && typeof data.case?.judge_text !== 'string') {
|
||||||
data.case.judge_text = formatStr(data.case.judge_text.message, ...data.case.judge_text.params);
|
data.case.judge_text = data.case.judge_text.message.format(data.case.judge_text.params);
|
||||||
}
|
}
|
||||||
data.key = 'next';
|
data.key = 'next';
|
||||||
data.tag = this.tag;
|
data.tag = this.tag;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import fs from 'fs-extra';
|
|||||||
import { noop } from 'lodash';
|
import { noop } from 'lodash';
|
||||||
import { Logger } from 'hydrooj/dist/logger';
|
import { Logger } from 'hydrooj/dist/logger';
|
||||||
import * as monitor from 'hydrooj/dist/service/monitor';
|
import * as monitor from 'hydrooj/dist/service/monitor';
|
||||||
|
import * as sysinfo from './sysinfo';
|
||||||
import * as tmpfs from './tmpfs';
|
import * as tmpfs from './tmpfs';
|
||||||
import { FormatError, CompileError, SystemError } from './error';
|
import { FormatError, CompileError, SystemError } from './error';
|
||||||
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from './status';
|
import { STATUS_COMPILE_ERROR, STATUS_SYSTEM_ERROR } from './status';
|
||||||
@@ -36,7 +37,6 @@ async function postInit() {
|
|||||||
// Only start a single daemon
|
// Only start a single daemon
|
||||||
if (!global.Hydro.isFirstWorker) return;
|
if (!global.Hydro.isFirstWorker) return;
|
||||||
const judge = require('./judge');
|
const judge = require('./judge');
|
||||||
const sysinfo = require('./sysinfo');
|
|
||||||
|
|
||||||
const { task, system } = global.Hydro.model;
|
const { task, system } = global.Hydro.model;
|
||||||
const { storage } = global.Hydro.service;
|
const { storage } = global.Hydro.service;
|
||||||
|
|||||||
@@ -1,23 +1,12 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import systeminformation from 'systeminformation';
|
|
||||||
import { noop } from 'lodash';
|
import { noop } from 'lodash';
|
||||||
|
import { get as _get } from '@hydrooj/utils/lib/sysinfo';
|
||||||
import { judge } from './judge/run';
|
import { judge } from './judge/run';
|
||||||
import * as tmpfs from './tmpfs';
|
import * as tmpfs from './tmpfs';
|
||||||
import { getConfig } from './config';
|
import { getConfig } from './config';
|
||||||
|
|
||||||
function size(s: number, base = 1) {
|
export { update } from '@hydrooj/utils/lib/sysinfo';
|
||||||
s *= base;
|
|
||||||
const unit = 1024;
|
|
||||||
const unitNames = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
|
||||||
for (const unitName of unitNames) {
|
|
||||||
if (s < unit) return `${Math.round(s * 10) / 10} ${unitName}`;
|
|
||||||
s /= unit;
|
|
||||||
}
|
|
||||||
return `${Math.round(s * unit)} ${unitNames[unitNames.length - 1]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cache: any = {};
|
|
||||||
|
|
||||||
async function stackSize() {
|
async function stackSize() {
|
||||||
let output = '';
|
let output = '';
|
||||||
@@ -35,8 +24,8 @@ int main(){
|
|||||||
main();
|
main();
|
||||||
}`,
|
}`,
|
||||||
config: {
|
config: {
|
||||||
time: 3000,
|
time: '3s',
|
||||||
memory: 256,
|
memory: '256m',
|
||||||
},
|
},
|
||||||
stat: {},
|
stat: {},
|
||||||
clean: [],
|
clean: [],
|
||||||
@@ -61,38 +50,10 @@ int main(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function get() {
|
export async function get() {
|
||||||
const [
|
const info = await _get();
|
||||||
Cpu, Memory, OsInfo,
|
// @ts-ignore
|
||||||
CurrentLoad, CpuFlags, CpuTemp,
|
info.stack = await stackSize();
|
||||||
Battery, stack,
|
return info;
|
||||||
] = await Promise.all([
|
|
||||||
systeminformation.cpu(),
|
|
||||||
systeminformation.mem(),
|
|
||||||
systeminformation.osInfo(),
|
|
||||||
systeminformation.currentLoad(),
|
|
||||||
systeminformation.cpuFlags(),
|
|
||||||
systeminformation.cpuTemperature(),
|
|
||||||
systeminformation.battery(),
|
|
||||||
stackSize(),
|
|
||||||
]);
|
|
||||||
const cpu = `${Cpu.manufacturer} ${Cpu.brand}`;
|
|
||||||
const memory = `${size(Memory.active)}/${size(Memory.total)}`;
|
|
||||||
const osinfo = `${OsInfo.distro} ${OsInfo.release} ${OsInfo.codename} ${OsInfo.kernel} ${OsInfo.arch}`;
|
|
||||||
const load = `${CurrentLoad.avgLoad}`;
|
|
||||||
const flags = CpuFlags;
|
|
||||||
let battery;
|
|
||||||
if (!Battery.hasBattery) battery = 'No battery';
|
|
||||||
else battery = `${Battery.type} ${Battery.model} ${Battery.percent}%${Battery.isCharging ? ' Charging' : ''}`;
|
|
||||||
const mid = OsInfo.serial;
|
|
||||||
cache.cpu = cpu;
|
|
||||||
cache.osinfo = osinfo;
|
|
||||||
cache.flags = flags;
|
|
||||||
cache.mid = mid;
|
|
||||||
cache.stack = stack;
|
|
||||||
global.reqCount = 0;
|
|
||||||
return {
|
|
||||||
mid, cpu, memory, osinfo, load, flags, CpuTemp, battery, stack, reqCount: 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -102,31 +63,3 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update() {
|
|
||||||
const [Memory, CurrentLoad, CpuTemp, Battery] = await Promise.all([
|
|
||||||
systeminformation.mem(),
|
|
||||||
systeminformation.currentLoad(),
|
|
||||||
systeminformation.cpuTemperature(),
|
|
||||||
systeminformation.battery(),
|
|
||||||
]);
|
|
||||||
const {
|
|
||||||
mid, cpu, osinfo, flags, stack,
|
|
||||||
} = cache;
|
|
||||||
const memory = `${size(Memory.active)}/${size(Memory.total)}`;
|
|
||||||
const load = `${CurrentLoad.avgLoad}`;
|
|
||||||
let battery;
|
|
||||||
if (!Battery.hasBattery) battery = 'No battery';
|
|
||||||
else battery = `${Battery.type} ${Battery.model} ${Battery.percent}%${Battery.isCharging ? ' Charging' : ''}`;
|
|
||||||
const reqCount = global.reqCount;
|
|
||||||
global.reqCount = 0;
|
|
||||||
return [
|
|
||||||
mid,
|
|
||||||
{
|
|
||||||
memory, load, battery, CpuTemp, reqCount,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mid, cpu, memory, osinfo, load, flags, battery, CpuTemp, stack, reqCount,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -5,34 +5,9 @@ import _ from 'lodash';
|
|||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { FormatError } from './error';
|
import { FormatError } from './error';
|
||||||
|
|
||||||
const TIME_RE = /^([0-9]+(?:\.[0-9]*)?)([mu]?)s?$/i;
|
|
||||||
const TIME_UNITS = { '': 1000, m: 1, u: 0.001 };
|
|
||||||
const MEMORY_RE = /^([0-9]+(?:\.[0-9]*)?)([kmg])b?$/i;
|
|
||||||
const MEMORY_UNITS = { k: 1 / 1024, m: 1, g: 1024 };
|
|
||||||
const EMPTY_STR = /^[ \r\n\t]*$/i;
|
const EMPTY_STR = /^[ \r\n\t]*$/i;
|
||||||
|
|
||||||
export const cmd = parse;
|
export const cmd = parse;
|
||||||
export function noop() { }
|
|
||||||
|
|
||||||
export function parseTimeMS(val: string | number) {
|
|
||||||
if (typeof val === 'number') return val;
|
|
||||||
const match = TIME_RE.exec(val);
|
|
||||||
if (!match) throw new FormatError('Error parsing time: {0}', [val]);
|
|
||||||
return Math.floor(parseFloat(match[1]) * TIME_UNITS[match[2]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseMemoryMB(val: string | number) {
|
|
||||||
if (typeof val === 'number') return val;
|
|
||||||
const match = MEMORY_RE.exec(val);
|
|
||||||
if (!match) throw new FormatError('Error parsing memory: {0}', [val]);
|
|
||||||
return Math.floor(parseFloat(match[1]) * MEMORY_UNITS[match[2]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sleep(timeout: number) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(resolve, timeout);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseFilename(filePath: string) {
|
export function parseFilename(filePath: string) {
|
||||||
const t = filePath.split('/');
|
const t = filePath.split('/');
|
||||||
@@ -112,3 +87,5 @@ export function ensureFile(folder: string) {
|
|||||||
return f;
|
return f;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export * from '@hydrooj/utils/lib/utils';
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.21.1",
|
"version": "2.21.2",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"typings": "dist/loader.d.ts",
|
"typings": "dist/loader.d.ts",
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hydrooj/utils": "^1.0.0",
|
||||||
"adm-zip": "^0.5.5",
|
"adm-zip": "^0.5.5",
|
||||||
"ansi_up": "^5.0.0",
|
"ansi_up": "^5.0.0",
|
||||||
"cookies": "^0.8.0",
|
"cookies": "^0.8.0",
|
||||||
@@ -34,7 +35,6 @@
|
|||||||
"serialize-javascript": "^5.0.1",
|
"serialize-javascript": "^5.0.1",
|
||||||
"sockjs": "^0.3.20",
|
"sockjs": "^0.3.20",
|
||||||
"superagent": "^6.1.0",
|
"superagent": "^6.1.0",
|
||||||
"systeminformation": "5.6.10",
|
|
||||||
"yargs": "^16.2.0"
|
"yargs": "^16.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -44,7 +44,15 @@ export async function load() {
|
|||||||
const storage = require('../service/storage');
|
const storage = require('../service/storage');
|
||||||
storage.start(sopts);
|
storage.start(sopts);
|
||||||
if (argv.loaderDetail) logger.info('finish: storage.connect');
|
if (argv.loaderDetail) logger.info('finish: storage.connect');
|
||||||
for (const i of builtinLib) require(`../lib/${i}`);
|
for (const i of builtinLib) {
|
||||||
|
let t;
|
||||||
|
try {
|
||||||
|
t = require.resolve(`../lib/${i}`);
|
||||||
|
} catch (e) {
|
||||||
|
t = require.resolve(`@hydrooj/utils/lib/${i}`);
|
||||||
|
}
|
||||||
|
require(t);
|
||||||
|
}
|
||||||
if (argv.loaderDetail) logger.info('finish: lib.builtin');
|
if (argv.loaderDetail) logger.info('finish: lib.builtin');
|
||||||
await lib(pending, fail);
|
await lib(pending, fail);
|
||||||
if (argv.loaderDetail) logger.info('finish: lib.extra');
|
if (argv.loaderDetail) logger.info('finish: lib.extra');
|
||||||
|
|||||||
@@ -540,7 +540,6 @@ export interface Lib extends Record<string, any> {
|
|||||||
rank: typeof import('./lib/rank'),
|
rank: typeof import('./lib/rank'),
|
||||||
rating: typeof import('./lib/rating'),
|
rating: typeof import('./lib/rating'),
|
||||||
testdataConfig: typeof import('./lib/testdataConfig'),
|
testdataConfig: typeof import('./lib/testdataConfig'),
|
||||||
sysinfo: typeof import('./lib/sysinfo'),
|
|
||||||
'testdata.convert.ini': typeof import('./lib/testdata.convert.ini'),
|
'testdata.convert.ini': typeof import('./lib/testdata.convert.ini'),
|
||||||
useragent: typeof import('./lib/useragent'),
|
useragent: typeof import('./lib/useragent'),
|
||||||
validator: typeof import('./lib/validator'),
|
validator: typeof import('./lib/validator'),
|
||||||
|
|||||||
@@ -2,44 +2,10 @@ const locales = {};
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface String {
|
interface String {
|
||||||
format: (...args: Array<any>) => string;
|
|
||||||
formatFromArray: (args: any[]) => string;
|
|
||||||
rawformat: (object: any) => string;
|
|
||||||
translate: (...languages: string[]) => string;
|
translate: (...languages: string[]) => string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String.prototype.format = function formatStr(...args) {
|
|
||||||
let result = this;
|
|
||||||
if (args.length > 0) {
|
|
||||||
if (args.length === 1 && typeof (args[0]) === 'object') {
|
|
||||||
for (const key in args) {
|
|
||||||
if (args[key] !== undefined) {
|
|
||||||
const reg = new RegExp(`(\\{${key}\\})`, 'g');
|
|
||||||
result = result.replace(reg, args[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else return this.formatFromArray(args);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
String.prototype.formatFromArray = function formatStr(args) {
|
|
||||||
let result = this;
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
if (args[i] !== undefined) {
|
|
||||||
const reg = new RegExp(`(\\{)${i}(\\})`, 'g');
|
|
||||||
result = result.replace(reg, args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
String.prototype.rawformat = function rawFormat(object) {
|
|
||||||
const res = this.split('{@}');
|
|
||||||
return [res[0], object, res[1]].join();
|
|
||||||
};
|
|
||||||
|
|
||||||
String.prototype.translate = function translate(...languages: string[]) {
|
String.prototype.translate = function translate(...languages: string[]) {
|
||||||
for (const language of languages) {
|
for (const language of languages) {
|
||||||
if (!language) continue;
|
if (!language) continue;
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import AnsiUp from 'ansi_up';
|
import AnsiUp from 'ansi_up';
|
||||||
import { ObjectID } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
|
import { size, formatSeconds } from '@hydrooj/utils/lib/utils';
|
||||||
import { md5 } from './crypto';
|
import { md5 } from './crypto';
|
||||||
|
|
||||||
|
export { size, formatSeconds } from '@hydrooj/utils/lib/utils';
|
||||||
|
|
||||||
const AU = new AnsiUp();
|
const AU = new AnsiUp();
|
||||||
|
|
||||||
export function ansiToHtml(str: string) {
|
export function ansiToHtml(str: string) {
|
||||||
@@ -49,30 +52,6 @@ export function* paginate(page: number, numPages: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function size(s: number, base = 1) {
|
|
||||||
s *= base;
|
|
||||||
const unit = 1024;
|
|
||||||
const unitNames = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
|
||||||
for (const unitName of unitNames) {
|
|
||||||
if (s < unit) return '{0} {1}'.format(Math.round(s * 10) / 10, unitName);
|
|
||||||
s /= unit;
|
|
||||||
}
|
|
||||||
return `${Math.round(s * unit)} ${unitNames[unitNames.length - 1]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _digit2(number: number) {
|
|
||||||
return number < 10 ? `0${number}` : number.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatSeconds(_seconds = '0') {
|
|
||||||
const seconds = parseInt(_seconds, 10);
|
|
||||||
return '{0}:{1}:{2}'.format(
|
|
||||||
_digit2(Math.floor(seconds / 3600)),
|
|
||||||
_digit2(Math.floor((seconds % 3600) / 60)),
|
|
||||||
_digit2(seconds % 60),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.lib.misc = {
|
global.Hydro.lib.misc = {
|
||||||
gravatar, datetimeSpan, paginate, size, formatSeconds, ansiToHtml,
|
gravatar, datetimeSpan, paginate, size, formatSeconds, ansiToHtml,
|
||||||
};
|
};
|
||||||
@@ -2,11 +2,11 @@ import cluster from 'cluster';
|
|||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import superagent from 'superagent';
|
import superagent from 'superagent';
|
||||||
import { dump } from 'js-yaml';
|
import { dump } from 'js-yaml';
|
||||||
|
import * as sysinfo from '@hydrooj/utils/lib/sysinfo';
|
||||||
|
import type { StatusUpdate } from '@hydrooj/utils/lib/sysinfo';
|
||||||
import db from './db';
|
import db from './db';
|
||||||
import * as bus from './bus';
|
import * as bus from './bus';
|
||||||
import * as sysinfo from '../lib/sysinfo';
|
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import type { StatusUpdate } from '../lib/sysinfo';
|
|
||||||
|
|
||||||
const coll = db.collection('status');
|
const coll = db.collection('status');
|
||||||
const logger = new Logger('monitor');
|
const logger = new Logger('monitor');
|
||||||
|
|||||||
@@ -1,246 +1,17 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import { Duplex } from 'stream';
|
|
||||||
import cluster from 'cluster';
|
import cluster from 'cluster';
|
||||||
import path, { sep } from 'path';
|
|
||||||
import { ObjectID } from 'mongodb';
|
|
||||||
import { isMoment } from 'moment';
|
|
||||||
import type { Moment } from 'moment-timezone';
|
|
||||||
import type { Logger } from './logger';
|
import type { Logger } from './logger';
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface StringConstructor {
|
|
||||||
random: (digit?: number) => string;
|
|
||||||
}
|
|
||||||
interface ArrayConstructor {
|
|
||||||
isDiff: (a: any[], b: any[]) => boolean;
|
|
||||||
}
|
|
||||||
interface Date {
|
|
||||||
format: (fmt?: string) => string;
|
|
||||||
}
|
|
||||||
interface Math {
|
|
||||||
sum: (...args: Array<number[] | number>) => number;
|
|
||||||
}
|
|
||||||
interface SetConstructor {
|
|
||||||
isSuperset: (set: Set<any>, subset: Set<any>) => boolean;
|
|
||||||
intersection: <T>(setA: Set<T>, setB: Set<T>) => Set<T>;
|
|
||||||
union: <T>(setA: Set<T>, setB: Set<T>) => Set<T>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cluster.worker) {
|
if (!cluster.worker) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
cluster.worker = { id: 0 };
|
cluster.worker = { id: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const dict = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
|
||||||
|
|
||||||
String.random = function random(digit = 32) {
|
|
||||||
let str = '';
|
|
||||||
for (let i = 1; i <= digit; i++) str += dict[Math.floor(Math.random() * 62)];
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.isDiff = function isDiff(a, b) {
|
|
||||||
if (a.length !== b.length) return true;
|
|
||||||
a.sort();
|
|
||||||
b.sort();
|
|
||||||
for (const i in a) {
|
|
||||||
if (a[i] !== b[i]) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Date.prototype.format = function formatDate(fmt = '%Y-%m-%d %H:%M:%S') {
|
|
||||||
let m = this.getMonth() + 1;
|
|
||||||
if (m < 10) m = `0${m}`;
|
|
||||||
let d = this.getDate();
|
|
||||||
if (d < 10) d = `0${d}`;
|
|
||||||
let H = this.getHours();
|
|
||||||
if (H < 10) H = `0${H}`;
|
|
||||||
let M = this.getMinutes();
|
|
||||||
if (M < 10) M = `0${M}`;
|
|
||||||
let S = this.getSeconds();
|
|
||||||
if (S < 10) S = `0${S}`;
|
|
||||||
return fmt
|
|
||||||
.replace('%Y', this.getFullYear())
|
|
||||||
.replace('%m', m)
|
|
||||||
.replace('%d', d)
|
|
||||||
.replace('%H', H)
|
|
||||||
.replace('%M', M)
|
|
||||||
.replace('%S', S);
|
|
||||||
};
|
|
||||||
|
|
||||||
Math.sum = function sum(...args) {
|
|
||||||
let s = 0;
|
|
||||||
for (const i of args) {
|
|
||||||
if (i instanceof Array) {
|
|
||||||
for (const j of i) {
|
|
||||||
s += j;
|
|
||||||
}
|
|
||||||
} else s += i;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
};
|
|
||||||
|
|
||||||
Set.isSuperset = function isSuperset(set, subset) {
|
|
||||||
for (const elem of subset) {
|
|
||||||
if (!set.has(elem)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Set.union = function Union<T>(setA: Set<T>, setB: Set<T>) {
|
|
||||||
const union = new Set(setA);
|
|
||||||
for (const elem of setB) union.add(elem);
|
|
||||||
return union;
|
|
||||||
};
|
|
||||||
|
|
||||||
Set.intersection = function Intersection<T>(setA: Set<T>, setB: Set<T>): Set<T> {
|
|
||||||
const intersection = new Set();
|
|
||||||
for (const elem of setB) {
|
|
||||||
if (setA.has(elem)) intersection.add(elem);
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
return intersection;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function folderSize(folderPath: string) {
|
|
||||||
let size = 0;
|
|
||||||
const _next = function a(p: string) {
|
|
||||||
if (p) {
|
|
||||||
const stats = fs.statSync(p);
|
|
||||||
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
||||||
if (!stats.isSymbolicLink()) size += stats.size;
|
|
||||||
} else {
|
|
||||||
size += stats.size;
|
|
||||||
const files = fs.readdirSync(p);
|
|
||||||
if (Array.isArray(files)) {
|
|
||||||
files.forEach((file) => {
|
|
||||||
_next(path.join(p, file));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_next(folderPath);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TIME_RE = /^([0-9]+(?:\.[0-9]*)?)([mu]?)s?$/i;
|
|
||||||
const TIME_UNITS = { '': 1000, m: 1, u: 0.001 };
|
|
||||||
const MEMORY_RE = /^([0-9]+(?:\.[0-9]*)?)([kmg])b?$/i;
|
|
||||||
const MEMORY_UNITS = { k: 1 / 1024, m: 1, g: 1024 };
|
|
||||||
|
|
||||||
export function parseTimeMS(str: string) {
|
|
||||||
const match = TIME_RE.exec(str);
|
|
||||||
if (!match) throw new Error(`${str} error parsing time`);
|
|
||||||
return Math.floor(parseFloat(match[1]) * TIME_UNITS[match[2]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseMemoryMB(str: string) {
|
|
||||||
const match = MEMORY_RE.exec(str);
|
|
||||||
if (!match) throw new Error(`${str} error parsing memory`);
|
|
||||||
return Math.ceil(parseFloat(match[1]) * MEMORY_UNITS[match[2]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isClass(obj: any, strict = false) {
|
|
||||||
if (typeof obj !== 'function') return false;
|
|
||||||
const str = obj.toString();
|
|
||||||
if (obj.prototype === undefined) return false;
|
|
||||||
if (obj.prototype.constructor !== obj) return false;
|
|
||||||
if (str.slice(0, 5) === 'class') return true;
|
|
||||||
if (Object.getOwnPropertyNames(obj.prototype).length >= 2) return true;
|
|
||||||
if (/^function\s+\(|^function\s+anonymous\(/.test(str)) return false;
|
|
||||||
if (strict && /^function\s+[A-Z]/.test(str)) return true;
|
|
||||||
if (/\b\(this\b|\bthis[.[]\b/.test(str)) {
|
|
||||||
if (!strict || /classCallCheck\(this/.test(str)) return true;
|
|
||||||
return /^function\sdefault_\d+\s*\(/.test(str);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function streamToBuffer(stream): Promise<Buffer> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const buffers = [];
|
|
||||||
stream.on('error', reject);
|
|
||||||
stream.on('data', (data) => buffers.push(data));
|
|
||||||
stream.on('end', () => resolve(Buffer.concat(buffers)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bufferToStream(buffer: Buffer): NodeJS.ReadableStream {
|
|
||||||
const stream = new Duplex();
|
|
||||||
stream.push(buffer);
|
|
||||||
stream.push(null);
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildProjection(fields: string[]): Record<string, 1> {
|
export function buildProjection(fields: string[]): Record<string, 1> {
|
||||||
const o = {};
|
const o = {};
|
||||||
for (const k of fields) o[k] = 1;
|
for (const k of fields) o[k] = 1;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sleep(timeout: number) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(resolve, timeout);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deepen(modifyString: (source: string) => string) {
|
|
||||||
function modifyObject<T>(source: T): T {
|
|
||||||
if (typeof source !== 'object' || !source) return source;
|
|
||||||
if (Array.isArray(source)) return source.map(modifyObject) as any;
|
|
||||||
const result = {} as T;
|
|
||||||
for (const key in source) {
|
|
||||||
result[modifyString(key)] = modifyObject(source[key]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return function t<T>(source: T): T {
|
|
||||||
if (typeof source === 'string') return modifyString(source) as any;
|
|
||||||
return modifyObject(source);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logAndReturn(logger: Logger) {
|
|
||||||
return function cb(err: Error) {
|
|
||||||
logger.error(err);
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const camelCase = deepen((source) => source.replace(/[_-][a-z]/g, (str) => str.slice(1).toUpperCase()));
|
|
||||||
export const paramCase = deepen((source) => source.replace(/_/g, '-').replace(/(?<!^)[A-Z]/g, (str) => `-${str.toLowerCase()}`));
|
|
||||||
export const snakeCase = deepen((source) => source.replace(/-/g, '_').replace(/(?<!^)[A-Z]/g, (str) => `_${str.toLowerCase()}`));
|
|
||||||
|
|
||||||
export namespace Time {
|
|
||||||
export const second = 1000;
|
|
||||||
export const minute = second * 60;
|
|
||||||
export const hour = minute * 60;
|
|
||||||
export const day = hour * 24;
|
|
||||||
export const week = day * 7;
|
|
||||||
export function formatTimeShort(ms: number) {
|
|
||||||
const abs = Math.abs(ms);
|
|
||||||
if (abs >= day - hour / 2) return `${Math.round(ms / day)}d`;
|
|
||||||
if (abs >= hour - minute / 2) return `${Math.round(ms / hour)}h`;
|
|
||||||
if (abs >= minute - second / 2) return `${Math.round(ms / minute)}m`;
|
|
||||||
if (abs >= second) return `${Math.round(ms / second)}s`;
|
|
||||||
return `${ms}ms`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getObjectID(timestamp: string | Date | Moment) {
|
|
||||||
let _timestamp: number;
|
|
||||||
if (typeof timestamp === 'string') _timestamp = new Date(timestamp).getTime();
|
|
||||||
else if (isMoment(timestamp)) _timestamp = timestamp.toDate().getTime();
|
|
||||||
else _timestamp = timestamp.getTime();
|
|
||||||
const hexSeconds = Math.floor(_timestamp / 1000).toString(16);
|
|
||||||
const constructedObjectId = new ObjectID(`${hexSeconds}0000000000000000`);
|
|
||||||
return constructedObjectId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const log2 = (val: bigint | number) => {
|
export const log2 = (val: bigint | number) => {
|
||||||
if (typeof val === 'bigint') {
|
if (typeof val === 'bigint') {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -250,19 +21,15 @@ export const log2 = (val: bigint | number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function errorMessage(err: Error | string) {
|
|
||||||
const t = typeof err === 'string' ? err : err.stack;
|
|
||||||
const q = t.split('\n');
|
|
||||||
for (let i = 0; i < q.length; i++) {
|
|
||||||
if (!q[i].startsWith(' at')) continue;
|
|
||||||
if (q[i].includes(`${sep}@hydrooj${sep}`)) q[i] = q[i].split(`@hydrooj${sep}`)[1];
|
|
||||||
else if (q[i].includes(`${sep}hydrooj${sep}`)) q[i] = `hydrooj${sep}${q[i].split(`hydrooj/${sep}`)[1]}`;
|
|
||||||
}
|
|
||||||
if (typeof err === 'string') return q.join('\n');
|
|
||||||
err.stack = q.join('\n');
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ArgMethod(target: any, funcName: string, obj: any) {
|
export function ArgMethod(target: any, funcName: string, obj: any) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function logAndReturn(logger: Logger) {
|
||||||
|
return function cb(err: Error) {
|
||||||
|
logger.error(err);
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export * from '@hydrooj/utils/lib/utils';
|
||||||
@@ -52,5 +52,3 @@ export async function update(): Promise<[string, StatusUpdate, StatusFull]> {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.lib.sysinfo = { get, update };
|
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
import path, { sep } from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { Duplex } from 'stream';
|
||||||
|
import { ObjectID } from 'bson';
|
||||||
|
import { isMoment } from 'moment';
|
||||||
|
import type { Moment } from 'moment-timezone';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface StringConstructor {
|
||||||
|
random: (digit?: number) => string;
|
||||||
|
}
|
||||||
|
interface String {
|
||||||
|
format: (...args: Array<any>) => string;
|
||||||
|
formatFromArray: (args: any[]) => string;
|
||||||
|
rawformat: (object: any) => string;
|
||||||
|
}
|
||||||
|
interface ArrayConstructor {
|
||||||
|
isDiff: (a: any[], b: any[]) => boolean;
|
||||||
|
}
|
||||||
|
interface Date {
|
||||||
|
format: (fmt?: string) => string;
|
||||||
|
}
|
||||||
|
interface Math {
|
||||||
|
sum: (...args: Array<number[] | number>) => number;
|
||||||
|
}
|
||||||
|
interface SetConstructor {
|
||||||
|
isSuperset: (set: Set<any>, subset: Set<any>) => boolean;
|
||||||
|
intersection: <T>(setA: Set<T>, setB: Set<T>) => Set<T>;
|
||||||
|
union: <T>(setA: Set<T>, setB: Set<T>) => Set<T>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dict = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
||||||
|
|
||||||
|
String.random = function random(digit = 32) {
|
||||||
|
let str = '';
|
||||||
|
for (let i = 1; i <= digit; i++) str += dict[Math.floor(Math.random() * 62)];
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.format = function formatStr(...args) {
|
||||||
|
let result = this;
|
||||||
|
if (args.length > 0) {
|
||||||
|
if (args.length === 1 && typeof (args[0]) === 'object') {
|
||||||
|
for (const key in args) {
|
||||||
|
if (args[key] !== undefined) {
|
||||||
|
const reg = new RegExp(`(\\{${key}\\})`, 'g');
|
||||||
|
result = result.replace(reg, args[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else return this.formatFromArray(args);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.formatFromArray = function formatStr(args) {
|
||||||
|
let result = this;
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] !== undefined) {
|
||||||
|
const reg = new RegExp(`(\\{)${i}(\\})`, 'g');
|
||||||
|
result = result.replace(reg, args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.rawformat = function rawFormat(object) {
|
||||||
|
const res = this.split('{@}');
|
||||||
|
return [res[0], object, res[1]].join();
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.isDiff = function isDiff(a, b) {
|
||||||
|
if (a.length !== b.length) return true;
|
||||||
|
a.sort();
|
||||||
|
b.sort();
|
||||||
|
for (const i in a) {
|
||||||
|
if (a[i] !== b[i]) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Date.prototype.format = function formatDate(fmt = '%Y-%m-%d %H:%M:%S') {
|
||||||
|
let m = this.getMonth() + 1;
|
||||||
|
if (m < 10) m = `0${m}`;
|
||||||
|
let d = this.getDate();
|
||||||
|
if (d < 10) d = `0${d}`;
|
||||||
|
let H = this.getHours();
|
||||||
|
if (H < 10) H = `0${H}`;
|
||||||
|
let M = this.getMinutes();
|
||||||
|
if (M < 10) M = `0${M}`;
|
||||||
|
let S = this.getSeconds();
|
||||||
|
if (S < 10) S = `0${S}`;
|
||||||
|
return fmt
|
||||||
|
.replace('%Y', this.getFullYear())
|
||||||
|
.replace('%m', m)
|
||||||
|
.replace('%d', d)
|
||||||
|
.replace('%H', H)
|
||||||
|
.replace('%M', M)
|
||||||
|
.replace('%S', S);
|
||||||
|
};
|
||||||
|
|
||||||
|
Math.sum = function sum(...args) {
|
||||||
|
let s = 0;
|
||||||
|
for (const i of args) {
|
||||||
|
if (i instanceof Array) {
|
||||||
|
for (const j of i) {
|
||||||
|
s += j;
|
||||||
|
}
|
||||||
|
} else s += i;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.isSuperset = function isSuperset(set, subset) {
|
||||||
|
for (const elem of subset) {
|
||||||
|
if (!set.has(elem)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.union = function Union<T>(setA: Set<T>, setB: Set<T>) {
|
||||||
|
const union = new Set(setA);
|
||||||
|
for (const elem of setB) union.add(elem);
|
||||||
|
return union;
|
||||||
|
};
|
||||||
|
|
||||||
|
Set.intersection = function Intersection<T>(setA: Set<T>, setB: Set<T>): Set<T> {
|
||||||
|
const intersection = new Set();
|
||||||
|
for (const elem of setB) {
|
||||||
|
if (setA.has(elem)) intersection.add(elem);
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return intersection;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function folderSize(folderPath: string) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||||
|
let size = 0;
|
||||||
|
const _next = function a(p: string) {
|
||||||
|
if (p) {
|
||||||
|
const stats = fs.statSync(p);
|
||||||
|
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
||||||
|
if (!stats.isSymbolicLink()) size += stats.size;
|
||||||
|
} else {
|
||||||
|
size += stats.size;
|
||||||
|
const files = fs.readdirSync(p);
|
||||||
|
if (Array.isArray(files)) {
|
||||||
|
files.forEach((file) => {
|
||||||
|
_next(path.join(p, file));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_next(folderPath);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIME_RE = /^([0-9]+(?:\.[0-9]*)?)([mu]?)s?$/i;
|
||||||
|
const TIME_UNITS = { '': 1000, m: 1, u: 0.001 };
|
||||||
|
const MEMORY_RE = /^([0-9]+(?:\.[0-9]*)?)([kmg])b?$/i;
|
||||||
|
const MEMORY_UNITS = { k: 1 / 1024, m: 1, g: 1024 };
|
||||||
|
|
||||||
|
export function parseTimeMS(str: string) {
|
||||||
|
const match = TIME_RE.exec(str);
|
||||||
|
if (!match) throw new Error(`${str} error parsing time`);
|
||||||
|
return Math.floor(parseFloat(match[1]) * TIME_UNITS[match[2]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseMemoryMB(str: string) {
|
||||||
|
const match = MEMORY_RE.exec(str);
|
||||||
|
if (!match) throw new Error(`${str} error parsing memory`);
|
||||||
|
return Math.ceil(parseFloat(match[1]) * MEMORY_UNITS[match[2]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isClass(obj: any, strict = false) {
|
||||||
|
if (typeof obj !== 'function') return false;
|
||||||
|
const str = obj.toString();
|
||||||
|
if (obj.prototype === undefined) return false;
|
||||||
|
if (obj.prototype.constructor !== obj) return false;
|
||||||
|
if (str.slice(0, 5) === 'class') return true;
|
||||||
|
if (Object.getOwnPropertyNames(obj.prototype).length >= 2) return true;
|
||||||
|
if (/^function\s+\(|^function\s+anonymous\(/.test(str)) return false;
|
||||||
|
if (strict && /^function\s+[A-Z]/.test(str)) return true;
|
||||||
|
if (/\b\(this\b|\bthis[.[]\b/.test(str)) {
|
||||||
|
if (!strict || /classCallCheck\(this/.test(str)) return true;
|
||||||
|
return /^function\sdefault_\d+\s*\(/.test(str);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function streamToBuffer(stream): Promise<Buffer> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const buffers = [];
|
||||||
|
stream.on('error', reject);
|
||||||
|
stream.on('data', (data) => buffers.push(data));
|
||||||
|
stream.on('end', () => resolve(Buffer.concat(buffers)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bufferToStream(buffer: Buffer): NodeJS.ReadableStream {
|
||||||
|
const stream = new Duplex();
|
||||||
|
stream.push(buffer);
|
||||||
|
stream.push(null);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sleep(timeout: number) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, timeout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepen(modifyString: (source: string) => string) {
|
||||||
|
function modifyObject<T>(source: T): T {
|
||||||
|
if (typeof source !== 'object' || !source) return source;
|
||||||
|
if (Array.isArray(source)) return source.map(modifyObject) as any;
|
||||||
|
const result = {} as T;
|
||||||
|
for (const key in source) {
|
||||||
|
result[modifyString(key)] = modifyObject(source[key]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function t<T>(source: T): T {
|
||||||
|
if (typeof source === 'string') return modifyString(source) as any;
|
||||||
|
return modifyObject(source);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function noop() { }
|
||||||
|
|
||||||
|
export const camelCase = deepen((source) => source.replace(/[_-][a-z]/g, (str) => str.slice(1).toUpperCase()));
|
||||||
|
export const paramCase = deepen((source) => source.replace(/_/g, '-').replace(/(?<!^)[A-Z]/g, (str) => `-${str.toLowerCase()}`));
|
||||||
|
export const snakeCase = deepen((source) => source.replace(/-/g, '_').replace(/(?<!^)[A-Z]/g, (str) => `_${str.toLowerCase()}`));
|
||||||
|
|
||||||
|
export namespace Time {
|
||||||
|
export const second = 1000;
|
||||||
|
export const minute = second * 60;
|
||||||
|
export const hour = minute * 60;
|
||||||
|
export const day = hour * 24;
|
||||||
|
export const week = day * 7;
|
||||||
|
export function formatTimeShort(ms: number) {
|
||||||
|
const abs = Math.abs(ms);
|
||||||
|
if (abs >= day - hour / 2) return `${Math.round(ms / day)}d`;
|
||||||
|
if (abs >= hour - minute / 2) return `${Math.round(ms / hour)}h`;
|
||||||
|
if (abs >= minute - second / 2) return `${Math.round(ms / minute)}m`;
|
||||||
|
if (abs >= second) return `${Math.round(ms / second)}s`;
|
||||||
|
return `${ms}ms`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getObjectID(timestamp: string | Date | Moment) {
|
||||||
|
let _timestamp: number;
|
||||||
|
if (typeof timestamp === 'string') _timestamp = new Date(timestamp).getTime();
|
||||||
|
else if (isMoment(timestamp)) _timestamp = timestamp.toDate().getTime();
|
||||||
|
else _timestamp = timestamp.getTime();
|
||||||
|
const hexSeconds = Math.floor(_timestamp / 1000).toString(16);
|
||||||
|
const constructedObjectId = new ObjectID(`${hexSeconds}0000000000000000`);
|
||||||
|
return constructedObjectId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function errorMessage(err: Error | string) {
|
||||||
|
const t = typeof err === 'string' ? err : err.stack;
|
||||||
|
const q = t.split('\n');
|
||||||
|
for (let i = 0; i < q.length; i++) {
|
||||||
|
if (!q[i].startsWith(' at')) continue;
|
||||||
|
if (q[i].includes(`${sep}@hydrooj${sep}`)) q[i] = q[i].split(`@hydrooj${sep}`)[1];
|
||||||
|
else if (q[i].includes(`${sep}hydrooj${sep}`)) q[i] = `hydrooj${sep}${q[i].split(`hydrooj/${sep}`)[1]}`;
|
||||||
|
}
|
||||||
|
if (typeof err === 'string') return q.join('\n');
|
||||||
|
err.stack = q.join('\n');
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function size(s: number, base = 1) {
|
||||||
|
s *= base;
|
||||||
|
const unit = 1024;
|
||||||
|
const unitNames = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||||
|
for (const unitName of unitNames) {
|
||||||
|
if (s < unit) return '{0} {1}'.format(Math.round(s * 10) / 10, unitName);
|
||||||
|
s /= unit;
|
||||||
|
}
|
||||||
|
return `${Math.round(s * unit)} ${unitNames[unitNames.length - 1]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _digit2(number: number) {
|
||||||
|
return number < 10 ? `0${number}` : number.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatSeconds(_seconds = '0') {
|
||||||
|
const seconds = parseInt(_seconds, 10);
|
||||||
|
return '{0}:{1}:{2}'.format(
|
||||||
|
_digit2(Math.floor(seconds / 3600)),
|
||||||
|
_digit2(Math.floor((seconds % 3600) / 60)),
|
||||||
|
_digit2(seconds % 60),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "@hydrooj/utils",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "hydrooj utils",
|
||||||
|
"main": "package.json",
|
||||||
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
"author": "undefined <i@undefined.moe>",
|
||||||
|
"license": "AGPL-3.0-only",
|
||||||
|
"dependencies": {
|
||||||
|
"bson": "^4.2.3",
|
||||||
|
"moment": "^2.29.1",
|
||||||
|
"systeminformation": "^5.6.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"moment-timezone": "^0.5.33"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user