From 1c3dc161b697bddaf70cdce5a5bed0cf1d847b3c Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 4 Oct 2022 01:38:51 +0800 Subject: [PATCH] core: fix types --- CHANGELOG.md | 7 ---- packages/hydrooj/src/context.ts | 2 +- packages/hydrooj/src/entry/common.ts | 3 +- packages/hydrooj/src/handler/problem.ts | 1 - packages/hydrooj/src/model/blog.ts | 3 -- packages/hydrooj/src/model/discussion.ts | 4 +- packages/hydrooj/src/model/record.ts | 29 ++++++++------- packages/hydrooj/src/model/task.ts | 2 +- packages/hydrooj/src/service/bus.ts | 47 +++++++++++------------- packages/hydrooj/src/service/db.ts | 3 +- packages/hydrooj/src/service/server.ts | 2 +- packages/hydrooj/src/settings.ts | 5 +-- packages/ui-default/index.ts | 2 +- 13 files changed, 48 insertions(+), 62 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d8ca12f40..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -## Changes for hydrooj@3: - -- 重构了 server 结构: -- - 移除了 `Handler.init` `Handler.finish` 方法。 -- - 移除了 `handler/finish` 钩子。 -- - 移除了 `requireCsrfToken` 。 -- - 移除了 `sockjs`,转为使用原生 `WebSocket` 。 diff --git a/packages/hydrooj/src/context.ts b/packages/hydrooj/src/context.ts index 9953dad66..e16f0f2c8 100644 --- a/packages/hydrooj/src/context.ts +++ b/packages/hydrooj/src/context.ts @@ -21,7 +21,7 @@ function provideModule(type: T, id: string, mo } export interface Context { - [Context.events]: Events; + [Context.events]: Events; loader: Loader; Route: typeof import('./service/server').Route; Connection: typeof import('./service/server').Connection; diff --git a/packages/hydrooj/src/entry/common.ts b/packages/hydrooj/src/entry/common.ts index 446cee94c..26ffec9ab 100644 --- a/packages/hydrooj/src/entry/common.ts +++ b/packages/hydrooj/src/entry/common.ts @@ -31,7 +31,8 @@ function locateFile(basePath: string, filenames: string[]) { return null; } -const getLoader = (type: string, filename: string) => async function loader(pending: string[], fail: string[], ctx: Context) { +type LoadTask = 'handler' | 'model' | 'addon' | 'lib' | 'script' | 'service'; +const getLoader = (type: LoadTask, filename: string) => async function loader(pending: string[], fail: string[], ctx: Context) { for (const i of pending) { const p = locateFile(i, [`${filename}.ts`, `${filename}.js`]); if (p && !fail.includes(i)) { diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index 260860501..89d5f5b6c 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -851,7 +851,6 @@ export class ProblemSolutionHandler extends ProblemDetailHandler { this.response.body = { psdocs, page, pcount, pscount, udict, pssdict, pdoc: this.pdoc, sid, }; - await bus.parallel('handler/solution/get', this); } @param('content', Types.Content) diff --git a/packages/hydrooj/src/model/blog.ts b/packages/hydrooj/src/model/blog.ts index d6d174409..ab3f6855b 100644 --- a/packages/hydrooj/src/model/blog.ts +++ b/packages/hydrooj/src/model/blog.ts @@ -1,7 +1,6 @@ import { omit } from 'lodash'; import { FilterQuery, ObjectID } from 'mongodb'; import { BlogDoc } from '../interface'; -import * as bus from '../service/bus'; import { NumberKeys } from '../typeutils'; import * as document from './document'; @@ -18,13 +17,11 @@ export async function add( updateAt: new Date(), views: 0, }; - await bus.parallel('blog/before-add', payload); const res = await document.add( 'system', payload.content!, payload.owner!, document.TYPE_BLOG, null, null, null, omit(payload, ['domainId', 'content', 'owner']), ); payload.docId = res; - await bus.emit('blog/add', payload); return payload.docId; } diff --git a/packages/hydrooj/src/model/discussion.ts b/packages/hydrooj/src/model/discussion.ts index a23600c7c..cb6602c0c 100644 --- a/packages/hydrooj/src/model/discussion.ts +++ b/packages/hydrooj/src/model/discussion.ts @@ -291,7 +291,7 @@ async function updateSort() { } } -export async function apply(ctx: Context) { +export function apply(ctx: Context) { ctx.using(['worker'], async ({ worker }) => { worker.addHandler('discussion.sort', updateSort); if (!await TaskModel.count({ type: 'schedule', subType: 'discussion.sort' })) { @@ -305,7 +305,7 @@ export async function apply(ctx: Context) { }); } -global.Hydro.model.DiscussionModel = { +global.Hydro.model.discussion = { typeDisplay, PROJECTION_LIST, PROJECTION_PUBLIC, diff --git a/packages/hydrooj/src/model/record.ts b/packages/hydrooj/src/model/record.ts index 118d7922e..f6d5af1b9 100644 --- a/packages/hydrooj/src/model/record.ts +++ b/packages/hydrooj/src/model/record.ts @@ -2,15 +2,15 @@ import { omit, sum } from 'lodash'; import moment from 'moment-timezone'; import { - Collection, FilterQuery, MatchKeysAndValues, + FilterQuery, MatchKeysAndValues, ObjectID, OnlyFieldsOfType, PushOperator, UpdateQuery, } from 'mongodb'; +import { Context } from '../context'; import { ProblemNotFoundError } from '../error'; import { FileInfo, JudgeMeta, JudgeRequest, ProblemConfigFile, RecordDoc, } from '../interface'; -import * as bus from '../service/bus'; import db from '../service/db'; import { MaybeArray, NumberKeys } from '../typeutils'; import { ArgMethod, buildProjection, Time } from '../utils'; @@ -18,8 +18,8 @@ import { STATUS } from './builtin'; import problem from './problem'; import task from './task'; -class RecordModel { - static coll: Collection = db.collection('record'); +export default class RecordModel { + static coll = db.collection('record'); static PROJECTION_LIST: (keyof RecordDoc)[] = [ '_id', 'score', 'time', 'memory', 'lang', 'uid', 'pid', 'rejudged', 'progress', 'domainId', @@ -230,15 +230,16 @@ class RecordModel { } } -// Mark problem as deleted -bus.on('problem/delete', (domainId, docId) => RecordModel.coll.updateMany({ domainId, pid: docId }, { $set: { pid: -1 } })); -bus.on('domain/delete', (domainId) => RecordModel.coll.deleteMany({ domainId })); -bus.on('ready', () => db.ensureIndexes( - RecordModel.coll, - { key: { domainId: 1, contest: 1, _id: -1 }, name: 'basic' }, - { key: { domainId: 1, contest: 1, uid: 1, _id: -1 }, name: 'withUser' }, - { key: { domainId: 1, contest: 1, pid: 1, _id: -1 }, name: 'withProblem' }, -)); +export function apply(ctx: Context) { + // Mark problem as deleted + ctx.on('problem/delete', (domainId, docId) => RecordModel.coll.updateMany({ domainId, pid: docId }, { $set: { pid: -1 } })); + ctx.on('domain/delete', (domainId) => RecordModel.coll.deleteMany({ domainId })); + ctx.on('ready', () => db.ensureIndexes( + RecordModel.coll, + { key: { domainId: 1, contest: 1, _id: -1 }, name: 'basic' }, + { key: { domainId: 1, contest: 1, uid: 1, _id: -1 }, name: 'withUser' }, + { key: { domainId: 1, contest: 1, pid: 1, _id: -1 }, name: 'withProblem' }, + )); +} -export default RecordModel; global.Hydro.model.record = RecordModel; diff --git a/packages/hydrooj/src/model/task.ts b/packages/hydrooj/src/model/task.ts index df71a18bb..368b36fe8 100644 --- a/packages/hydrooj/src/model/task.ts +++ b/packages/hydrooj/src/model/task.ts @@ -187,7 +187,7 @@ export async function apply(ctx: Context) { const handleEvent = async (doc: EventDoc) => { const payload = JSON.parse(doc.payload); if (process.send) process.send({ type: 'hydro:broadcast', data: { event: doc.event, payload } }); - await bus.parallel(doc.event, ...payload); + await (bus.parallel as any)(doc.event, ...payload); }; stream.on('change', async (change) => { if (change.operationType !== 'insert') return; diff --git a/packages/hydrooj/src/service/bus.ts b/packages/hydrooj/src/service/bus.ts index 27f9c9592..240a9204b 100644 --- a/packages/hydrooj/src/service/bus.ts +++ b/packages/hydrooj/src/service/bus.ts @@ -12,22 +12,26 @@ import type { Tdoc, TrainingDoc, User, } from '../interface'; import type { DocType } from '../model/document'; -import type { Handler } from './server'; +import type { ConnectionHandler, Handler } from './server'; export type Disposable = () => void; export type VoidReturn = Promise | any; +type HookType = 'before-prepare' | 'before' | 'after' | 'finish'; +type ModuleCategories = 'lib' | 'locale' | 'template' | 'script' | 'model' | 'setting' | 'handler' | 'service' | 'addon'; +type LifecycleEvents = Record<`app/load/${ModuleCategories}`, () => VoidReturn>; +type MapHandlerEvents = Record<`handler/${HookType}/${N}`, (thisArg: H) => VoidReturn>; +type KnownHandlerEvents = + MapHandlerEvents<'UserRegister', UserRegisterHandler> + & MapHandlerEvents<'ProblemSolution', ProblemSolutionHandler>; +type HandlerEvents = + KnownHandlerEvents + & Record<`handler/${HookType}/${string}`, (thisArg: Handler & Record) => VoidReturn> + & Record<`handler/${HookType}`, (thisArg: Handler) => VoidReturn> + & Record<`connection/${'create' | 'active' | 'close'}`, (thisArg: ConnectionHandler) => VoidReturn>; /* eslint-disable @typescript-eslint/naming-convention */ -export interface EventMap { +export interface EventMap extends LifecycleEvents, HandlerEvents { 'app/started': () => void - 'app/load/lib': () => VoidReturn - 'app/load/locale': () => VoidReturn - 'app/load/template': () => VoidReturn - 'app/load/script': () => VoidReturn - 'app/load/setting': () => VoidReturn - 'app/load/model': () => VoidReturn - 'app/load/handler': () => VoidReturn - 'app/load/service': () => VoidReturn 'app/ready': () => VoidReturn 'app/exit': () => VoidReturn @@ -59,16 +63,7 @@ export interface EventMap { 'handler/create': (thisArg: Handler) => VoidReturn 'handler/init': (thisArg: Handler) => VoidReturn - 'handler/before-prepare/UserRegister': (thisArg: UserRegisterHandler) => VoidReturn - 'handler/before-prepare': (thisArg: Handler) => VoidReturn - 'handler/before/UserRegister': (thisArg: UserRegisterHandler) => VoidReturn - 'handler/before': (thisArg: Handler) => VoidReturn - 'handler/after/UserRegister': (thisArg: UserRegisterHandler) => VoidReturn - 'handler/after': (thisArg: Handler) => VoidReturn - 'handler/finish/UserRegister': (thisArg: UserRegisterHandler) => VoidReturn - 'handler/finish': (thisArg: Handler) => VoidReturn 'handler/error': (thisArg: Handler, e: Error) => VoidReturn - 'handler/solution/get': (thisArg: ProblemSolutionHandler) => VoidReturn 'discussion/before-add': (payload: Partial) => VoidReturn 'discussion/add': (payload: Partial) => VoidReturn @@ -90,6 +85,8 @@ export interface EventMap { 'contest/before-add': (payload: Partial) => VoidReturn 'contest/add': (payload: Partial, id: ObjectID) => VoidReturn + 'oplog/log': (type: string, handler: Handler, args: any, data: any) => VoidReturn; + 'training/list': (query: FilterQuery, handler: any) => VoidReturn 'training/get': (tdoc: TrainingDoc, handler: any) => VoidReturn @@ -104,7 +101,7 @@ export function apply(ctx: Context) { pm2.launchBus((err, bus) => { if (err) throw new Error(); bus.on('hydro:broadcast', (packet) => { - ctx.parallel(packet.data.event, ...packet.data.payload); + (ctx.parallel as any)(packet.data.event, ...packet.data.payload); }); ctx.on('bus/broadcast', (event, payload) => { process.send({ type: 'hydro:broadcast', data: { event, payload } }); @@ -121,11 +118,11 @@ export default app; export const on = (a, b, c?) => app.on(a, b, c); export const off = (a, b) => app.off(a, b); export const once = (a, b, c?) => app.once(a, b, c); -export const parallel = (a, ...b) => app.parallel(a, ...b); -export const emit = (a, ...b) => app.parallel(a, ...b); -export const bail = (a, ...b) => app.bail(a, ...b); +export const parallel = app.parallel.bind(app); +export const emit = app.parallel.bind(app); +export const bail = app.bail.bind(app); // For backward compatibility -export const serial: any = (a, ...b) => app.parallel(a, ...b); -export const broadcast = (a, ...b) => app.broadcast(a, ...b); +export const serial: any = app.parallel.bind(app); +export const broadcast = app.broadcast.bind(app); global.Hydro.service.bus = app as any; diff --git a/packages/hydrooj/src/service/db.ts b/packages/hydrooj/src/service/db.ts index 884a4f20e..a165d3ee1 100644 --- a/packages/hydrooj/src/service/db.ts +++ b/packages/hydrooj/src/service/db.ts @@ -2,9 +2,10 @@ import { Collection, Db, IndexSpecification, MongoClient, } from 'mongodb'; -import { Collections } from '../interface'; import { Logger } from '../logger'; import options from '../options'; +// Note: this might be re-declared so we have to use Collections here +import type { Collections } from '../plugin-api'; import * as bus from './bus'; const logger = new Logger('mongo'); diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index 0d3753607..fd2d56d55 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -210,7 +210,7 @@ export class Handler extends HandlerCommon { } async function bail(name: string, ...args: any[]) { - const r = await bus.bail(name, ...args); + const r = await (bus.bail as any)(name, ...args); if (r instanceof Error) throw r; return r; } diff --git a/packages/hydrooj/src/settings.ts b/packages/hydrooj/src/settings.ts index eec9b9d7e..bc20d77d3 100644 --- a/packages/hydrooj/src/settings.ts +++ b/packages/hydrooj/src/settings.ts @@ -2,7 +2,6 @@ import yaml from 'js-yaml'; import { nanoid } from 'nanoid'; import Schema from 'schemastery'; import { Logger } from './logger'; -import * as bus from './service/bus'; import { NestKeys } from './typeutils'; const defaultPath = process.env.CI ? '/tmp/file' @@ -64,7 +63,7 @@ export async function saveConfig(config: any) { Schema.intersect(SystemSettings)(config); const value = yaml.dump(config); await global.Hydro.service.db.collection('system').updateOne({ _id: 'config' }, { $set: { value } }, { upsert: true }); - bus.broadcast('config/update'); + loadConfig(); } export async function setConfig(key: string, value: any) { const path = key.split('.'); @@ -109,5 +108,3 @@ export function requestConfig(s: Schema): { const builtin = requestConfig(builtinSettings); export const builtinConfig = builtin.config; export const setBuiltinConfig = builtin.setConfig; - -bus.on('config/update', loadConfig); diff --git a/packages/ui-default/index.ts b/packages/ui-default/index.ts index 81aa0b997..c9d82b99a 100644 --- a/packages/ui-default/index.ts +++ b/packages/ui-default/index.ts @@ -13,7 +13,7 @@ import { join, resolve } from 'path'; import convert from 'schemastery-jsonschema'; import markdown from './backendlib/markdown'; -declare module 'hydrooj' { +declare module 'hydrooj/src/interface' { interface UI { esbuildPlugins?: esbuild.Plugin[] }