framework: use @cordisjs/core instead

This commit is contained in:
undefined committed 2025-03-04 03:04:01 +08:00
1 parent 221283e8e8
commit 2c8c03153e
10 files changed
+86 -179

No files matched your search

+3 -1
View File
@@ -16,6 +16,9 @@
"@aws-sdk/lib-storage": "3.726.1",
"@aws-sdk/s3-presigned-post": "3.726.1",
"@aws-sdk/s3-request-presigner": "3.726.1",
"@cordisjs/core": "4.0.0-alpha.0",
"@cordisjs/logger": "1.0.0-alpha.0",
"@cordisjs/plugin-timer": "1.0.0-alpha.0",
"@graphql-tools/schema": "^10.0.18",
"@hydrooj/common": "workspace:^",
"@hydrooj/framework": "workspace:^",
@@ -25,7 +28,6 @@
"@yarnpkg/libzip": "^3.1.0",
"adm-zip": "0.5.14",
"cac": "^6.7.14",
"cordis": "4.0.0-alpha.0",
"csv-stringify": "^6.5.2",
"emoji-regex": "^10.4.0",
"emojis-list": "2.1.0",
+8 -97
View File
@@ -1,4 +1,6 @@
import * as cordis from 'cordis';
import * as cordis from '@cordisjs/core';
import { Logger } from '@cordisjs/logger';
import { TimerService } from '@cordisjs/plugin-timer';
import Schema from 'schemastery';
import type { ServerEvents, WebService } from '@hydrooj/framework';
import type { DomainDoc, GeoIP, ModuleInterfaces } from './interface';
@@ -9,7 +11,7 @@ import type { CheckService } from './service/check';
import type { } from './service/migration';
import type { ConnectionHandler, Handler } from './service/server';
export interface Events<C extends Context = Context> extends cordis.Events<C>, EventMap, ServerEvents<Handler, ConnectionHandler> { }
export interface Events<C extends Context = Context> extends cordis.Events<C>, EventMap { }
function addScript<K>(name: string, description: string, validate: Schema<K>, run: (args: K, report: any) => boolean | Promise<boolean>) {
if (global.Hydro.script[name]) throw new Error(`duplicate script ${name} registered.`);
@@ -25,11 +27,11 @@ function provideModule<T extends keyof ModuleInterfaces>(type: T, id: string, mo
export type EffectScope = cordis.EffectScope<Context>;
export { Disposable, Plugin, ScopeStatus } from 'cordis';
export { Disposable, Plugin, ScopeStatus } from '@cordisjs/core';
export interface Context extends cordis.Context, Pick<WebService, 'Route' | 'Connection' | 'withHandlerClass'> {
export interface Context extends cordis.Context {
// @ts-ignore
[Context.events]: Events<this>;
[Context.events]: Events<this> & ServerEvents<this>;
loader: Loader;
check: CheckService;
setImmediate: typeof setImmediate;
@@ -38,12 +40,6 @@ export interface Context extends cordis.Context, Pick<WebService, 'Route' | 'Con
injectUI: typeof inject;
broadcast: Context['emit'];
geoip?: GeoIP;
// TODO: move to @cordisjs/plugin-timer
setTimeout(callback: () => void, delay: number): () => void
setInterval(callback: () => void, delay: number): () => void
sleep(delay: number): Promise<void>
throttle<F extends (...args: any[]) => void>(callback: F, delay: number, noTrailing?: boolean): WithDispose<F>
debounce<F extends (...args: any[]) => void>(callback: F, delay: number): WithDispose<F>
}
export abstract class Service extends cordis.Service<Context> {
@@ -71,92 +67,6 @@ export class ApiMixin extends cordis.Service {
}
}
type WithDispose<T> = T & { dispose: () => void };
class TimerService extends Service {
constructor(ctx) {
super(ctx, '$timer');
ctx.mixin('$timer', ['setTimeout', 'setInterval', 'sleep', 'throttle', 'debounce']);
}
setTimeout(callback: () => void, delay: number) {
const dispose = this.ctx.effect(() => {
const timer = setTimeout(() => {
dispose();
callback();
}, delay);
return () => clearTimeout(timer);
});
return dispose;
}
setInterval(callback: () => void, delay: number) {
return this.ctx.effect(() => {
const timer = setInterval(callback, delay);
return () => clearInterval(timer);
});
}
sleep(delay: number) {
const caller = this.ctx;
return new Promise<void>((resolve, reject) => {
const dispose1 = this.setTimeout(() => {
dispose1();
dispose2(); // eslint-disable-line @typescript-eslint/no-use-before-define
resolve();
}, delay);
const dispose2 = caller.on('dispose', () => {
dispose1();
dispose2();
reject(new Error('Context has been disposed'));
});
});
}
private createWrapper(callback: (args: any[], check: () => boolean) => any, isDisposed = false) {
this.ctx.scope.assertActive();
let timer: number | NodeJS.Timeout | undefined;
const dispose = () => {
isDisposed = true;
remove(); // eslint-disable-line @typescript-eslint/no-use-before-define
clearTimeout(timer);
};
const wrapper: any = (...args: any[]) => {
clearTimeout(timer);
timer = callback(args, () => !isDisposed && this.ctx.scope.active);
};
wrapper.dispose = dispose;
const remove = this.ctx.scope.disposables.push(dispose);
return wrapper;
}
throttle<F extends (...args: any[]) => void>(callback: F, delay: number, noTrailing?: boolean): WithDispose<F> {
let lastCall = -Infinity;
const execute = (...args: any[]) => {
lastCall = Date.now();
callback(...args);
};
return this.createWrapper((args, isActive) => { // eslint-disable-line consistent-return
const now = Date.now();
const remaining = delay - (now - lastCall);
if (remaining <= 0) {
execute(...args);
} else if (isActive()) {
return setTimeout(execute, remaining, ...args);
}
}, noTrailing);
}
debounce<F extends (...args: any[]) => void>(callback: F, delay: number): WithDispose<F> {
return this.createWrapper((args, isActive) => {
if (!isActive()) return;
return setTimeout(callback, delay, ...args); // eslint-disable-line consistent-return
});
}
}
export class Context extends cordis.Context {
domain?: DomainDoc;
@@ -164,6 +74,7 @@ export class Context extends cordis.Context {
super();
this.plugin(ApiMixin);
this.plugin(TimerService);
this.plugin(Logger);
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
/* eslint-disable max-len */
/* eslint-disable no-await-in-loop */
import * as cordis from 'cordis';
import * as cordis from '@cordisjs/core';
import yaml from 'js-yaml';
import { Dictionary } from 'lodash';
import moment from 'moment-timezone';
@@ -295,7 +295,7 @@ SystemSetting(
// eslint-disable-next-line import/no-mutable-exports
export const langs: Record<string, LangConfig> = {};
declare module 'cordis' {
declare module '@cordisjs/core' {
interface Context {
setting: SettingService;
}
+4 -4
View File
@@ -17,7 +17,7 @@ import type { DocType } from '../model/document';
export type Disposable = () => void;
export type VoidReturn = Promise<any> | any;
type HookType = 'before-prepare' | 'before' | 'before-operation' | 'after' | 'finish';
type MapHandlerEvents<N extends string, H extends Handler> = Record<`handler/${HookType}/${N}`, (thisArg: H) => VoidReturn>;
type MapHandlerEvents<N extends string, H extends Handler<Context>> = Record<`handler/${HookType}/${N}`, (thisArg: H) => VoidReturn>;
type KnownHandlerEvents =
MapHandlerEvents<'UserRegister', UserRegisterHandler>
& MapHandlerEvents<'ProblemSolution', ProblemSolutionHandler>;
@@ -38,7 +38,7 @@ export interface EventMap extends KnownHandlerEvents {
'database/config': () => VoidReturn
'system/setting': (args: Record<string, any>) => VoidReturn
'bus/broadcast': (event: keyof EventMap | keyof ServerEvents, payload: any, trace?: string) => VoidReturn
'bus/broadcast': (event: keyof EventMap | keyof ServerEvents<Context>, payload: any, trace?: string) => VoidReturn
'monitor/update': (type: 'server' | 'judge', $set: any) => VoidReturn
'monitor/collect': (info: any) => VoidReturn
'api/update': () => void;
@@ -93,7 +93,7 @@ export interface EventMap extends KnownHandlerEvents {
'contest/balloon': (domainId: string, tid: ObjectId, bdoc: ContestBalloonDoc) => VoidReturn
'contest/del': (domainId: string, tid: ObjectId) => VoidReturn
'oplog/log': (type: string, handler: Handler, args: any, data: any) => VoidReturn;
'oplog/log': (type: string, handler: Handler<Context>, args: any, data: any) => VoidReturn;
'training/list': (query: Filter<TrainingDoc>, handler: any) => VoidReturn
'training/get': (tdoc: TrainingDoc, handler: any) => VoidReturn
@@ -103,7 +103,7 @@ export interface EventMap extends KnownHandlerEvents {
}
/* eslint-enable @typescript-eslint/naming-convention */
declare module 'cordis' {
declare module '@cordisjs/core' {
interface Events extends EventMap { }
}
+5 -7
View File
@@ -28,7 +28,7 @@ const ignoredLimit = `,${argv.options.ignoredLimit},`;
const logger = new Logger('server');
declare module '@hydrooj/framework' {
export interface HandlerCommon {
export interface HandlerCommon<C> {
domain: DomainDoc;
paginate<T>(cursor: FindCursor<T>, page: number, key: string): Promise<[docs: T[], numPages: number, count: number]>;
@@ -73,10 +73,9 @@ export function requireSudo(target: any, funcName: string, obj: any) {
export interface Handler {
domain: DomainDoc;
ctx: Context;
}
export class Handler extends HandlerOriginal {
constructor(_, ctx: Context) {
export class Handler extends HandlerOriginal<Context> {
constructor(_, ctx) {
super(_, ctx);
this.ctx = ctx.extend({ domain: this.domain });
this.renderHTML = ((orig) => function (name: string, args: Record<string, any>) {
@@ -114,10 +113,9 @@ export class Handler extends HandlerOriginal {
export interface ConnectionHandler {
domain: DomainDoc;
ctx: Context;
}
export class ConnectionHandler extends ConnectionHandlerOriginal {
constructor(_, ctx: Context) {
export class ConnectionHandler extends ConnectionHandlerOriginal<Context> {
constructor(_, ctx) {
super(_, ctx);
this.ctx = ctx.extend({ domain: this.domain });
}