mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
优化logger,修复serial与once同时使用导致的调用问题
This commit is contained in:
1 parent
6ba93841ea
commit
3e721fdd55
15 files changed
+260
-123
No files matched your search
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable consistent-return */
|
||||
/* eslint-disable no-await-in-loop */
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import path from 'path';
|
||||
import globby from 'globby';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "2.13.5",
|
||||
"version": "2.13.6",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "dist/loader.js",
|
||||
"typings": "dist/loader.d.ts",
|
||||
@@ -31,6 +31,7 @@
|
||||
"serialize-javascript": "^4.0.0",
|
||||
"sockjs": "^0.3.20",
|
||||
"superagent": "^6.1.0",
|
||||
"supports-color": "^7.2.0",
|
||||
"systeminformation": "^4.27.3",
|
||||
"yargs": "^15.4.1"
|
||||
},
|
||||
@@ -49,6 +50,7 @@
|
||||
"@types/serialize-javascript": "^4.0.0",
|
||||
"@types/sockjs": "^0.3.32",
|
||||
"@types/superagent": "^4.1.8",
|
||||
"@types/supports-color": "^5.3.0",
|
||||
"@types/yargs": "^15.0.5"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import yaml from 'js-yaml';
|
||||
import { argv } from 'yargs';
|
||||
import { Logger } from '../logger';
|
||||
|
||||
const logger = new Logger('common', true);
|
||||
|
||||
export const builtinLib = [
|
||||
'jwt', 'download', 'i18n', 'mail', 'useragent',
|
||||
@@ -46,14 +48,12 @@ export async function handler(pending: string[], fail: string[]) {
|
||||
const p = path.resolve(i, 'handler.js');
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
console.log(`Handler init: ${i}`);
|
||||
console.time(`Handler init: ${i}`);
|
||||
logger.info('Handler init: %s', i);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Handler init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
console.error(`Handler Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Handler Load Fail: %s', i);
|
||||
logger.error('%o', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,11 +72,11 @@ export async function locale(pending: string[], fail: string[]) {
|
||||
locales[file.split('.')[0]] = yaml.safeLoad(content);
|
||||
}
|
||||
global.Hydro.lib.i18n(locales);
|
||||
console.log(`Locale init: ${i}`);
|
||||
logger.info('Locale init: %s', i);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
console.error(`Locale Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Locale Load Fail: %s', i);
|
||||
logger.error('%o', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,8 +105,8 @@ export async function setting(pending: string[], fail: string[], modelSetting: t
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Config Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Config Load Fail: %s', i);
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,11 +124,11 @@ export async function template(pending: string[], fail: string[]) {
|
||||
path.resolve(p, file),
|
||||
).toString();
|
||||
}
|
||||
console.log(`Template init: ${i}`);
|
||||
logger.info('Template init: %s', i);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
console.error(`Template Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Template Load Fail: %s', i);
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,14 +152,12 @@ export async function model(pending: string[], fail: string[]) {
|
||||
const p = path.resolve(i, 'model.js');
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
console.log(`Model init: ${i}`);
|
||||
console.time(`Model init: ${i}`);
|
||||
logger.info('Model init: %s', i);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Model init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
console.error(`Model Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Model Load Fail: %s', i);
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,14 +168,12 @@ export async function lib(pending: string[], fail: string[]) {
|
||||
const p = path.resolve(i, 'lib.js');
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
console.log(`Lib init: ${i}`);
|
||||
console.time(`Lib init: ${i}`);
|
||||
logger.info('Lib init: %s', i);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Lib init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
console.error(`Lib Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Lib Load Fail: %s', i);
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,14 +184,12 @@ export async function service(pending: string[], fail: string[]) {
|
||||
const p = path.resolve(i, 'service.js');
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
console.log(`Service init: ${i}`);
|
||||
console.time(`Service init: ${i}`);
|
||||
logger.info('Service init: %s', i);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Service init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
console.error(`Service Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Service Load Fail: %s', i);
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,13 +200,12 @@ export async function script(pending: string[], fail: string[], active: string[]
|
||||
const p = path.resolve(i, 'script.js');
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
console.time(`Script init: ${i}`);
|
||||
logger.info('Script init: %s', i);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Script init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
console.error(`Script Load Fail: ${i}`);
|
||||
if (argv.debug) console.error(e);
|
||||
logger.error('Script Load Fail: %s', i);
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
active.push(i);
|
||||
|
||||
@@ -47,11 +47,7 @@ export async function load(call: Entry) {
|
||||
fs.removeSync(lockfile);
|
||||
});
|
||||
await new Promise((resolve) => {
|
||||
const h = () => {
|
||||
console.log('Database connected');
|
||||
resolve();
|
||||
};
|
||||
bus.once('database/connect', h);
|
||||
bus.once('database/connect', resolve);
|
||||
require('../service/db');
|
||||
});
|
||||
require('../service/monitor');
|
||||
|
||||
@@ -7,6 +7,9 @@ import Body from 'koa-body';
|
||||
import cache from 'koa-static-cache';
|
||||
import mongodb from 'mongodb';
|
||||
import { argv } from 'yargs';
|
||||
import { Logger } from '../logger';
|
||||
|
||||
const logger = new Logger('setup');
|
||||
|
||||
const listenPort = argv.port || 8888;
|
||||
|
||||
@@ -141,5 +144,5 @@ export function load() {
|
||||
return get(ctx);
|
||||
});
|
||||
server.listen(listenPort);
|
||||
console.log('Server listening at:', listenPort);
|
||||
logger.success('Server listening at: %d', listenPort);
|
||||
}
|
||||
@@ -20,11 +20,7 @@ export async function load() {
|
||||
uistatic(pending, fail),
|
||||
]);
|
||||
await new Promise((resolve) => {
|
||||
const h = () => {
|
||||
console.log('Database connected');
|
||||
resolve();
|
||||
};
|
||||
bus.once('database/connect', h);
|
||||
bus.once('database/connect', resolve);
|
||||
require('../service/db');
|
||||
});
|
||||
for (const i of builtinLib) require(`../lib/${i}`);
|
||||
|
||||
@@ -510,6 +510,7 @@ declare global {
|
||||
stat: any,
|
||||
ui: UI,
|
||||
error: typeof import('./error'),
|
||||
Logger: typeof import('./logger'),
|
||||
locales: Dict<Dict<string>>,
|
||||
},
|
||||
addons: string[],
|
||||
|
||||
@@ -40,14 +40,14 @@ if (!global.Hydro) {
|
||||
global.addons = [];
|
||||
}
|
||||
|
||||
if (argv.debug) {
|
||||
console.log(process.argv);
|
||||
console.log(argv);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/first
|
||||
import { Logger } from './logger';
|
||||
// eslint-disable-next-line import/first
|
||||
import * as bus from './service/bus';
|
||||
|
||||
const logger = new Logger('loader');
|
||||
logger.debug('%o', argv);
|
||||
|
||||
async function terminate() {
|
||||
try {
|
||||
await bus.parallel('app/exit');
|
||||
@@ -113,9 +113,9 @@ async function executeCommand(input: string) {
|
||||
}
|
||||
|
||||
async function reload(count = 1) {
|
||||
console.log('Reloading');
|
||||
logger.info('Reloading');
|
||||
await stopWorker();
|
||||
console.log('Worker stopped');
|
||||
logger.info('Worker stopped');
|
||||
await startWorker(count);
|
||||
}
|
||||
|
||||
@@ -176,13 +176,13 @@ export function addon(addonPath: string) {
|
||||
if (fs.existsSync(publicPath)) fs.copySync(publicPath, publicTemp);
|
||||
global.addons.push(targetPath);
|
||||
} catch (e) {
|
||||
console.error('Addon load fail: ', e);
|
||||
logger.error('Addon load fail: ', e);
|
||||
throw e;
|
||||
}
|
||||
} else throw new Error(`Addon not found: ${addonPath}`);
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', (e) => console.error(e));
|
||||
process.on('unhandledRejection', logger.error);
|
||||
process.on('SIGINT', terminate);
|
||||
|
||||
export async function load() {
|
||||
@@ -191,7 +191,7 @@ export async function load() {
|
||||
process.on('message', messageHandler);
|
||||
cluster.on('message', messageHandler);
|
||||
if (cluster.isMaster || argv.startAsMaster) {
|
||||
console.log(`Master ${process.pid} Starting`);
|
||||
logger.info(`Master ${process.pid} Starting`);
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.on('data', (buf) => {
|
||||
const input = buf.toString();
|
||||
@@ -205,33 +205,33 @@ export async function load() {
|
||||
}
|
||||
});
|
||||
const cnt = await entry({ entry: 'master' });
|
||||
console.log('Master started');
|
||||
logger.info('Master started');
|
||||
cluster.on('exit', (worker, code, signal) => {
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} exit: ${code} ${signal}`);
|
||||
logger.info(`Worker ${worker.process.pid} ${worker.id} exit: ${code} ${signal}`);
|
||||
});
|
||||
cluster.on('disconnect', (worker) => {
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} disconnected`);
|
||||
logger.info(`Worker ${worker.process.pid} ${worker.id} disconnected`);
|
||||
});
|
||||
cluster.on('listening', (worker, address) => {
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} listening at `, address);
|
||||
logger.info(`Worker ${worker.process.pid} ${worker.id} listening at `, address);
|
||||
});
|
||||
cluster.on('online', (worker) => {
|
||||
console.log(`Worker ${worker.process.pid} ${worker.id} is online`);
|
||||
logger.success(`Worker ${worker.process.pid} ${worker.id} is online`);
|
||||
});
|
||||
await startWorker(cnt);
|
||||
} else {
|
||||
global.addons = JSON.parse(Buffer.from(argv.addons as string, 'base64').toString());
|
||||
console.log(global.addons);
|
||||
logger.info('%o', global.addons);
|
||||
if (argv.entry) {
|
||||
console.log(`Worker ${process.pid} Starting as ${argv.entry}`);
|
||||
logger.info(`Worker ${process.pid} Starting as ${argv.entry}`);
|
||||
await entry({ entry: argv.entry as string });
|
||||
console.log(`Worker ${process.pid} Started as ${argv.entry}`);
|
||||
logger.success(`Worker ${process.pid} Started as ${argv.entry}`);
|
||||
} else {
|
||||
if (argv.firstWorker) cluster.isFirstWorker = true;
|
||||
else cluster.isFirstWorker = false;
|
||||
console.log(`Worker ${process.pid} Starting`);
|
||||
logger.info(`Worker ${process.pid} Starting`);
|
||||
await entry({ entry: 'worker' });
|
||||
console.log(`Worker ${process.pid} Started`);
|
||||
logger.success(`Worker ${process.pid} Started`);
|
||||
}
|
||||
}
|
||||
if (global.gc) global.gc();
|
||||
@@ -245,7 +245,7 @@ export async function loadCli() {
|
||||
if (argv.pandora || !module.parent) {
|
||||
const func = argv._[0] === 'cli' ? load : loadCli;
|
||||
func().catch((e) => {
|
||||
console.error(e);
|
||||
logger.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import { inspect, InspectOptions, format } from 'util';
|
||||
import { argv } from 'yargs';
|
||||
import { stderr } from 'supports-color';
|
||||
|
||||
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`;
|
||||
}
|
||||
}
|
||||
|
||||
const colors = stderr.level < 2 ? [6, 2, 3, 4, 5, 1] : [
|
||||
20, 21, 26, 27, 32, 33, 38, 39, 40, 41, 42, 43, 44, 45, 56, 57, 62,
|
||||
63, 68, 69, 74, 75, 76, 77, 78, 79, 80, 81, 92, 93, 98, 99, 112, 113,
|
||||
129, 134, 135, 148, 149, 160, 161, 162, 163, 164, 165, 166, 167, 168,
|
||||
169, 170, 171, 172, 173, 178, 179, 184, 185, 196, 197, 198, 199, 200,
|
||||
201, 202, 203, 204, 205, 206, 207, 208, 209, 214, 215, 220, 221,
|
||||
];
|
||||
|
||||
const instances: Record<string, Logger> = {};
|
||||
|
||||
type LogFunction = (format: any, ...param: any[]) => void
|
||||
|
||||
type LogType = 'success' | 'error' | 'info' | 'warn' | 'debug'
|
||||
|
||||
export interface Logger extends Record<LogType, LogFunction> { }
|
||||
|
||||
export class Logger {
|
||||
static readonly SUCCESS = 1
|
||||
|
||||
static readonly ERROR = 1
|
||||
|
||||
static readonly INFO = 2
|
||||
|
||||
static readonly WARN = 2
|
||||
|
||||
static readonly DEBUG = 3
|
||||
|
||||
static baseLevel = argv.debug ? 3 : 2
|
||||
|
||||
static showDiff = false
|
||||
|
||||
static levels: Record<string, number> = {}
|
||||
|
||||
static lastTime = 0
|
||||
|
||||
static options: InspectOptions = {
|
||||
colors: stderr.hasBasic,
|
||||
}
|
||||
|
||||
static formatters: Record<string, (this: Logger, value: any) => string> = {
|
||||
c: Logger.prototype.color,
|
||||
C: (value) => Logger.color(15, value, ';1'),
|
||||
o: (value) => inspect(value, Logger.options).replace(/\s*\n\s*/g, ' '),
|
||||
}
|
||||
|
||||
static color(code: number, value: any, decoration = '') {
|
||||
if (!Logger.options.colors) return `${value}`;
|
||||
return `\u001B[3${code < 8 ? code : `8;5;${code}`}${decoration}m${value}\u001B[0m`;
|
||||
}
|
||||
|
||||
private code: number
|
||||
|
||||
private displayName: string
|
||||
|
||||
public stream: NodeJS.WritableStream = process.stderr
|
||||
|
||||
constructor(public name: string, private showDiff = false) {
|
||||
if (name in instances) return instances[name];
|
||||
let hash = 0;
|
||||
for (let i = 0; i < name.length; i++) {
|
||||
hash = ((hash << 3) - hash) + name.charCodeAt(i);
|
||||
hash |= 0;
|
||||
}
|
||||
instances[name] = this;
|
||||
this.code = colors[Math.abs(hash) % colors.length];
|
||||
this.displayName = name ? this.color(`${name} `, ';1') : '';
|
||||
this.createMethod('success', '[S] ', Logger.SUCCESS);
|
||||
this.createMethod('error', '[E] ', Logger.ERROR);
|
||||
this.createMethod('info', '[I] ', Logger.INFO);
|
||||
this.createMethod('warn', '[W] ', Logger.WARN);
|
||||
this.createMethod('debug', '[D] ', Logger.DEBUG);
|
||||
}
|
||||
|
||||
private color(value: any, decoration = '') {
|
||||
return Logger.color(this.code, value, decoration);
|
||||
}
|
||||
|
||||
private createMethod(name: LogType, prefix: string, minLevel: number) {
|
||||
this[name] = (...args: [any, ...any[]]) => {
|
||||
if (this.level < minLevel) return;
|
||||
this.stream.write(`${prefix + this.displayName + this.format(...args)}\n`);
|
||||
};
|
||||
}
|
||||
|
||||
get level() {
|
||||
return Logger.levels[this.name] ?? Logger.baseLevel;
|
||||
}
|
||||
|
||||
extend = (namespace: string, showDiff = this.showDiff) => new Logger(`${this.name}:${namespace}`, showDiff)
|
||||
|
||||
format: (format: any, ...param: any[]) => string = (...args) => {
|
||||
if (args[0] instanceof Error) args[0] = args[0].stack || args[0].message;
|
||||
else if (typeof args[0] !== 'string') args.unshift('%O');
|
||||
let index = 0;
|
||||
args[0] = (args[0] as string).replace(/%([a-zA-Z%])/g, (match, fmt) => {
|
||||
if (match === '%%') return '%';
|
||||
index += 1;
|
||||
const formatter = Logger.formatters[fmt];
|
||||
if (typeof formatter === 'function') {
|
||||
match = formatter.call(this, args[index]);
|
||||
args.splice(index, 1);
|
||||
index -= 1;
|
||||
}
|
||||
return match;
|
||||
}).split('\n').join('\n ');
|
||||
if (Logger.showDiff || this.showDiff) {
|
||||
const now = Date.now();
|
||||
if (Logger.lastTime) {
|
||||
args.push(this.color(`+${Time.formatTimeShort(now - Logger.lastTime)}`));
|
||||
}
|
||||
Logger.lastTime = now;
|
||||
}
|
||||
return format(...args);
|
||||
}
|
||||
}
|
||||
|
||||
global.Hydro.Logger = { Logger };
|
||||
@@ -528,8 +528,8 @@ export function count(domainId: string, query: any, type: Type = document.TYPE_C
|
||||
return document.count(domainId, type, query);
|
||||
}
|
||||
|
||||
export function getMulti<K extends Type & keyof document.DocumentType>(
|
||||
domainId: string, query: FilterQuery<document.DocumentType[K]> = {}, type?: K,
|
||||
export function getMulti<K extends Type & keyof document.DocType>(
|
||||
domainId: string, query: FilterQuery<document.DocType[K]> = {}, type?: K,
|
||||
) {
|
||||
return document.getMulti(domainId, type || document.TYPE_CONTEST, query);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export const TYPE_TRAINING = 40;
|
||||
export const TYPE_FILE = 50;
|
||||
export const TYPE_HOMEWORK = 60;
|
||||
|
||||
export interface DocumentType {
|
||||
export interface DocType {
|
||||
[TYPE_PROBLEM]: Pdoc,
|
||||
[TYPE_PROBLEM_SOLUTION]: any,
|
||||
[TYPE_PROBLEM_LIST]: any,
|
||||
@@ -35,13 +35,13 @@ export interface DocumentType {
|
||||
[TYPE_HOMEWORK]: Tdoc,
|
||||
}
|
||||
|
||||
export async function add<T extends DocID, K extends keyof DocumentType>(
|
||||
export async function add<T extends DocID, K extends keyof DocType>(
|
||||
domainId: string, content: string, owner: number,
|
||||
docType: K, docId: DocumentType[K]['docId'],
|
||||
docType: K, docId: DocType[K]['docId'],
|
||||
parentType?: number | null, parentId?: DocID,
|
||||
args?: any,
|
||||
): Promise<T>
|
||||
export async function add<K extends keyof DocumentType>(
|
||||
export async function add<K extends keyof DocType>(
|
||||
domainId: string, content: string, owner: number,
|
||||
docType: K, docId: null,
|
||||
parentType?: number, parentId?: DocID,
|
||||
@@ -73,13 +73,13 @@ export async function add(
|
||||
return docId || res.insertedId;
|
||||
}
|
||||
|
||||
export function get<K extends keyof DocumentType>(domainId: string, docType: K, docId: DocumentType[K]['docId']) {
|
||||
export function get<K extends keyof DocType>(domainId: string, docType: K, docId: DocType[K]['docId']) {
|
||||
return coll.findOne({ domainId, docType, docId });
|
||||
}
|
||||
|
||||
export async function set<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, docId: DocumentType[K]['docId'], $set: Partial<DocumentType[K]>,
|
||||
): Promise<DocumentType[K]> {
|
||||
export async function set<K extends keyof DocType>(
|
||||
domainId: string, docType: K, docId: DocType[K]['docId'], $set: Partial<DocType[K]>,
|
||||
): Promise<DocType[K]> {
|
||||
await bus.parallel('document/set', domainId, docType, docId, $set);
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
@@ -89,8 +89,8 @@ export async function set<K extends keyof DocumentType>(
|
||||
return res.value;
|
||||
}
|
||||
|
||||
export function deleteOne<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, docId: DocumentType[K]['docId'],
|
||||
export function deleteOne<K extends keyof DocType>(
|
||||
domainId: string, docType: K, docId: DocType[K]['docId'],
|
||||
) {
|
||||
return Promise.all([
|
||||
collStatus.deleteMany({ domainId, docType, docId }),
|
||||
@@ -98,27 +98,27 @@ export function deleteOne<K extends keyof DocumentType>(
|
||||
]);
|
||||
}
|
||||
|
||||
export function deleteMulti<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocumentType[K]>,
|
||||
export function deleteMulti<K extends keyof DocType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocType[K]>,
|
||||
) {
|
||||
return coll.deleteMany({ ...query, domainId, docType });
|
||||
}
|
||||
|
||||
export function deleteMultiStatus<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocumentType[K]>,
|
||||
export function deleteMultiStatus<K extends keyof DocType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocType[K]>,
|
||||
) {
|
||||
return collStatus.deleteMany({ ...query, domainId, docType });
|
||||
}
|
||||
|
||||
export function getMulti<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocumentType[K]>,
|
||||
): Cursor<DocumentType[K]> {
|
||||
export function getMulti<K extends keyof DocType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocType[K]>,
|
||||
): Cursor<DocType[K]> {
|
||||
return coll.find({ ...query, docType, domainId });
|
||||
}
|
||||
|
||||
export async function inc<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, docId: DocumentType[K]['docId'],
|
||||
key: NumberKeys<DocumentType[K]>, value: number,
|
||||
export async function inc<K extends keyof DocType>(
|
||||
domainId: string, docType: K, docId: DocType[K]['docId'],
|
||||
key: NumberKeys<DocType[K]>, value: number,
|
||||
) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
@@ -128,11 +128,11 @@ export async function inc<K extends keyof DocumentType>(
|
||||
return res.value;
|
||||
}
|
||||
|
||||
type Q = NumberKeys<DocumentType[10]>
|
||||
type Q = NumberKeys<DocType[10]>
|
||||
|
||||
export async function incAndSet<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, docId: DocumentType[K]['docId'],
|
||||
key: NumberKeys<DocumentType[K]>, value: number, args: Partial<DocumentType[K]>,
|
||||
export async function incAndSet<K extends keyof DocType>(
|
||||
domainId: string, docType: K, docId: DocType[K]['docId'],
|
||||
key: NumberKeys<DocType[K]>, value: number, args: Partial<DocType[K]>,
|
||||
) {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
@@ -142,15 +142,15 @@ export async function incAndSet<K extends keyof DocumentType>(
|
||||
return res.value;
|
||||
}
|
||||
|
||||
export function count<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocumentType[K]>,
|
||||
export function count<K extends keyof DocType>(
|
||||
domainId: string, docType: K, query?: FilterQuery<DocType[K]>,
|
||||
) {
|
||||
return coll.find({ ...query, docType, domainId }).count();
|
||||
}
|
||||
|
||||
export async function push<K extends keyof DocumentType, T extends keyof DocumentType[K]>(
|
||||
domainId: string, docType: K, docId: DocumentType[K]['docId'],
|
||||
key: keyof DocumentType[K], content: string, owner: number, args: DocumentType[K][T][0] = {},
|
||||
export async function push<K extends keyof DocType, T extends keyof DocType[K]>(
|
||||
domainId: string, docType: K, docId: DocType[K]['docId'],
|
||||
key: keyof DocType[K], content: string, owner: number, args: DocType[K][T][0] = {},
|
||||
) {
|
||||
const _id = new ObjectID();
|
||||
const doc = await coll.findOneAndUpdate(
|
||||
@@ -167,10 +167,10 @@ export async function push<K extends keyof DocumentType, T extends keyof Documen
|
||||
return [doc.value, _id];
|
||||
}
|
||||
|
||||
export async function pull<K extends keyof DocumentType>(
|
||||
domainId: string, docType: K, docId: DocumentType[K]['docId'],
|
||||
export async function pull<K extends keyof DocType>(
|
||||
domainId: string, docType: K, docId: DocType[K]['docId'],
|
||||
setKey: string, contents: string[],
|
||||
): Promise<DocumentType[K]> {
|
||||
): Promise<DocType[K]> {
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $pull: { [setKey]: { $in: contents } } },
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import cluster from 'cluster';
|
||||
import { Db, ObjectID } from 'mongodb';
|
||||
import { Db, UpdateQuery } from 'mongodb';
|
||||
import { Logger } from '../logger';
|
||||
import { Mdoc, Rdoc, User } from '../interface';
|
||||
// only typings.
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { DocType } from '../model/document';
|
||||
|
||||
const _hooks: Record<keyof any, Array<(...args: any[]) => any>> = {};
|
||||
const _disposables = [];
|
||||
const logger = new Logger('bus', true);
|
||||
|
||||
function isBailed(value: any) {
|
||||
return value !== null && value !== false && value !== undefined;
|
||||
@@ -12,7 +16,7 @@ function isBailed(value: any) {
|
||||
|
||||
export type Disposable = () => void
|
||||
|
||||
interface EventMap {
|
||||
export interface EventMap {
|
||||
'app/started': () => void
|
||||
'app/exit': () => Promise<void> | void
|
||||
'dispose': () => void
|
||||
@@ -22,15 +26,16 @@ interface EventMap {
|
||||
'user/message': (uid: number, mdoc: Mdoc, udoc: User) => void
|
||||
|
||||
'document/add': (doc: any) => Promise<void> | void
|
||||
'document/set': (domainId: string, docType: number, docId: ObjectID | string | number, $set: any) => Promise<void> | void
|
||||
'document/set': <T extends keyof DocType>
|
||||
(domainId: string, docType: T, docId: DocType[T], $set: UpdateQuery<DocType[T]>['$set']) => Promise<void> | void
|
||||
|
||||
'record/change': (rdoc: Rdoc, $set?: any, $push?: any) => void
|
||||
'record/change': (rdoc: Rdoc, $set?: UpdateQuery<Rdoc>['$set'], $push?: UpdateQuery<Rdoc>['$push']) => void
|
||||
}
|
||||
|
||||
function getHooks<K extends keyof EventMap>(name: K) {
|
||||
const hooks = _hooks[name] || (_hooks[name] = []);
|
||||
if (hooks.length >= 128) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
'max listener count (128) for event "%s" exceeded, which may be caused by a memory leak',
|
||||
name,
|
||||
);
|
||||
@@ -49,23 +54,17 @@ export function removeListener<K extends keyof EventMap>(name: K, listener: Even
|
||||
|
||||
export function addListener<K extends keyof EventMap>(name: K, listener: EventMap[K]) {
|
||||
getHooks(name).push(listener);
|
||||
const dispose = () => removeListener(name, listener);
|
||||
_disposables.push(name === 'dispose' ? listener as Disposable : dispose);
|
||||
return dispose;
|
||||
return () => removeListener(name, listener);
|
||||
}
|
||||
|
||||
export function prependListener<K extends keyof EventMap>(name: K, listener: EventMap[K]) {
|
||||
getHooks(name).unshift(listener);
|
||||
const dispose = () => removeListener(name, listener);
|
||||
_disposables.push(name === 'dispose' ? listener as Disposable : dispose);
|
||||
return dispose;
|
||||
return () => removeListener(name, listener);
|
||||
}
|
||||
|
||||
export function once<K extends keyof EventMap>(name: K, listener: EventMap[K]) {
|
||||
// @ts-ignore
|
||||
const dispose = addListener(name, (...args: Parameters<EventMap[K]>) => {
|
||||
const dispose = addListener(name, function _listener(...args: any[]) {
|
||||
dispose();
|
||||
// @ts-ignore
|
||||
return listener.apply(this, args);
|
||||
});
|
||||
return dispose;
|
||||
@@ -91,12 +90,12 @@ export function emit<K extends keyof EventMap>(name: K, ...args: Parameters<Even
|
||||
return parallel(name, ...args);
|
||||
}
|
||||
|
||||
export async function serial<K extends keyof EventMap>(name: K, ...args: Parameters<EventMap[K]>): Promise<ReturnType<EventMap[K]>> {
|
||||
for (const callback of _hooks[name] || []) {
|
||||
const result = await callback.apply(this, args);
|
||||
if (isBailed(result)) return result;
|
||||
export async function serial<K extends keyof EventMap>(name: K, ...args: Parameters<EventMap[K]>): Promise<void> {
|
||||
logger.debug('serial: %s', name, args);
|
||||
const hooks = Array.from(_hooks[name]);
|
||||
for (const callback of hooks) {
|
||||
await callback.apply(this, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function bail<K extends keyof EventMap>(name: K, ...args: Parameters<EventMap[K]>): ReturnType<EventMap[K]> {
|
||||
|
||||
@@ -18,6 +18,7 @@ import serialize, { SerializeJSOptions } from 'serialize-javascript';
|
||||
import { argv } from 'yargs';
|
||||
import { lrucache } from '../utils';
|
||||
import { User, DomainDoc } from '../interface';
|
||||
import { Logger } from '../logger';
|
||||
import {
|
||||
UserNotFoundError, BlacklistedError, PermissionError,
|
||||
UserFacingError, ValidationError, PrivilegeError,
|
||||
@@ -33,6 +34,7 @@ import * as blacklist from '../model/blacklist';
|
||||
import * as token from '../model/token';
|
||||
import * as opcount from '../model/opcount';
|
||||
|
||||
const logger = new Logger('server');
|
||||
export const app = new Koa();
|
||||
export const server = http.createServer(app.callback());
|
||||
export const router = new Router();
|
||||
@@ -762,7 +764,7 @@ export function Connection(
|
||||
RouteConnHandler: any,
|
||||
...permPrivChecker: Array<number | bigint | Function>
|
||||
) {
|
||||
const log = argv.debug ? console.log : () => { };
|
||||
const log = (v: string, fmt: string, ...args: any[]) => logger.debug(fmt, ...args);
|
||||
const sock = sockjs.createServer({ prefix, log });
|
||||
const checker = Checker(permPrivChecker);
|
||||
sock.on('connection', async (conn) => {
|
||||
@@ -792,7 +794,7 @@ export function Connection(
|
||||
if (h.finish) await h.finish(args);
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
logger.warn(e);
|
||||
await h.onerror(e);
|
||||
}
|
||||
});
|
||||
@@ -820,7 +822,7 @@ export async function start() {
|
||||
});
|
||||
app.use(router.routes()).use(router.allowedMethods());
|
||||
server.listen(argv.port || port);
|
||||
console.log('Server listening at: %s', argv.port || port);
|
||||
logger.success('Server listening at: %d', argv.port || port);
|
||||
}
|
||||
|
||||
global.Hydro.service.server = {
|
||||
|
||||
Reference in new issue
Block a user