优化logger,修复serial与once同时使用导致的调用问题

This commit is contained in:
undefined committed 2020-09-08 13:24:46 +08:00
1 parent 6ba93841ea
commit 3e721fdd55
15 files changed
+260 -123

No files matched your search

+1
View File
@@ -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
View File
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
/* eslint-disable import/no-extraneous-dependencies */
import os from 'os';
import path from 'path';
+1
View File
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
/* eslint-disable import/no-extraneous-dependencies */
import path from 'path';
import globby from 'globby';
+3 -1
View File
@@ -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": {
+26 -33
View File
@@ -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);
+1 -5
View File
@@ -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');
+4 -1
View File
@@ -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);
}
+1 -5
View File
@@ -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}`);
+1
View File
@@ -510,6 +510,7 @@ declare global {
stat: any,
ui: UI,
error: typeof import('./error'),
Logger: typeof import('./logger'),
locales: Dict<Dict<string>>,
},
addons: string[],
+21 -21
View File
@@ -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);
});
}
+142
View File
@@ -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 };
+2 -2
View File
@@ -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);
}
+32 -32
View File
@@ -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 } } },
+19 -20
View File
@@ -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]> {
+5 -3
View File
@@ -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 = {