From 28b3abf4410f2fbb4c8d4304b28ca07a801e6874 Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 5 Oct 2024 20:38:20 +0800 Subject: [PATCH] core: upgrade to context tracing --- framework/framework/server.ts | 22 ++++++++++------------ packages/hydrooj/src/context.ts | 6 ++++-- packages/hydrooj/src/handler/home.ts | 11 ++++------- packages/hydrooj/src/handler/misc.ts | 3 ++- packages/hydrooj/src/lib/i18n.ts | 10 ++++++---- packages/hydrooj/src/model/setting.ts | 8 +++++--- packages/hydrooj/src/service/check.ts | 8 +++++--- packages/hydrooj/src/service/worker.ts | 8 +++++--- packages/vjudge/src/index.ts | 4 +--- 9 files changed, 42 insertions(+), 38 deletions(-) diff --git a/framework/framework/server.ts b/framework/framework/server.ts index cc0828a89..c24ccfc76 100644 --- a/framework/framework/server.ts +++ b/framework/framework/server.ts @@ -338,7 +338,6 @@ export class WebService extends Service { HandlerCommon = HandlerCommon; Handler = Handler; ConnectionHandler = ConnectionHandler; - handlerCtxBase = this.ctx; constructor(ctx: Context, public config: WebServiceConfig) { super(ctx, 'server', true); @@ -439,9 +438,6 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); } socket.close(); }); - this.ctx.inject(['server'], (c) => { - this.handlerCtxBase = c; - }); } async listen() { @@ -460,7 +456,7 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); private async handleHttp(ctx: KoaContext, HandlerClass, checker) { const { args } = ctx.HydroContext; Object.assign(args, ctx.params); - const h = new HandlerClass(ctx, this.handlerCtxBase); + const h = new HandlerClass(ctx, this.ctx); ctx.handler = h; const method = ctx.method.toLowerCase(); try { @@ -534,7 +530,7 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); private async handleWS(ctx: KoaContext, HandlerClass, checker, conn, layer) { const { args } = ctx.HydroContext; - const h = new HandlerClass(ctx, this.handlerCtxBase); + const h = new HandlerClass(ctx, this.ctx); await this.ctx.parallel('connection/create', h); ctx.handler = h; h.conn = conn; @@ -599,8 +595,8 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); } private register(type: 'route' | 'conn', routeName: string, path: string, HandlerClass: any, ...permPrivChecker) { - const name = HandlerClass.name; if (!HandlerClass?.[kHandler] || !isClass(HandlerClass)) throw new Error('Invalid registration.'); + const name = HandlerClass.name; if (this.registrationCount[name] && this.registry[name] !== HandlerClass) { logger.warn('Route with name %s already exists.', name); } @@ -617,7 +613,7 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); const dispose = router.disposeLastOp; // @ts-ignore this.ctx.parallel(`handler/register/${name}`, HandlerClass); - this[Context.current]?.on('dispose', () => { + this.ctx.on('dispose', () => { this.registrationCount[name]--; if (!this.registrationCount[name]) delete this.registry[name]; dispose(); @@ -650,7 +646,7 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); const dispose = () => { this[name] = this[name].filter((i) => i !== layer); }; - this[Context.current]?.on('dispose', dispose); + this[Context.origin]?.on('dispose', dispose); return dispose; } @@ -683,9 +679,11 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); public registerRenderer(name: string, func: RendererFunction) { if (this.renderers[name]) logger.warn('Renderer %s already exists.', name); - this.renderers[name] = func; - this[Context.current]?.on('dispose', () => { - delete this.renderers[name]; + this.ctx.effect(() => { + this.renderers[name] = func; + return () => { + delete this.renderers[name]; + }; }); } } diff --git a/packages/hydrooj/src/context.ts b/packages/hydrooj/src/context.ts index f169a63e6..1c8a5faff 100644 --- a/packages/hydrooj/src/context.ts +++ b/packages/hydrooj/src/context.ts @@ -50,8 +50,10 @@ export abstract class Service extends cord const T = any>(origFunc: F, disposeFunc?) => function method(this: cordis.Service, ...args: Parameters) { - const res = origFunc(...args); - this[Context.current]?.on('dispose', () => (disposeFunc ? disposeFunc(res) : res())); + this.ctx.effect(() => { + const res = origFunc(...args); + return () => (disposeFunc ? disposeFunc(res) : res()); + }); }; export class ApiMixin extends Service { diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index 9d9ca5448..fa42f38ff 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -179,7 +179,6 @@ export class HomeHandler extends Handler { } } -let geoip: Context['geoip'] = null; class HomeSecurityHandler extends Handler { @requireSudo async get() { @@ -189,7 +188,7 @@ class HomeSecurityHandler extends Handler { session.isCurrent = session._id === this.session._id; session._id = md5(session._id); session.updateUa = useragent.parse(session.updateUa || session.createUa || ''); - session.updateGeoip = geoip?.lookup?.( + session.updateGeoip = this.ctx.geoip?.lookup?.( session.updateIp || session.createIp, this.translate('geoip_locale'), ); @@ -202,7 +201,7 @@ class HomeSecurityHandler extends Handler { 'credentialID', 'name', 'credentialType', 'credentialDeviceType', 'authenticatorAttachment', 'regat', 'fmt', ])), - geoipProvider: geoip?.provider, + geoipProvider: this.ctx?.geoip?.provider, icon: (str = '') => str.split(' ')[0].toLowerCase(), }; } @@ -591,10 +590,8 @@ class HomeMessagesConnectionHandler extends ConnectionHandler { } } -export async function apply(ctx: Context) { - ctx.inject(['geoip'], (g) => { - geoip = g.geoip; - }); +export const inject = { geoip: { required: false } }; +export function apply(ctx: Context) { ctx.Route('homepage', '/', HomeHandler); ctx.Route('home_security', '/home/security', HomeSecurityHandler, PRIV.PRIV_USER_PROFILE); ctx.Route('user_changemail_with_code', '/home/changeMail/:code', UserChangemailWithCodeHandler, PRIV.PRIV_USER_PROFILE); diff --git a/packages/hydrooj/src/handler/misc.ts b/packages/hydrooj/src/handler/misc.ts index aff58df8d..d695969aa 100644 --- a/packages/hydrooj/src/handler/misc.ts +++ b/packages/hydrooj/src/handler/misc.ts @@ -2,6 +2,7 @@ import { statSync } from 'fs'; import { pick } from 'lodash'; import { lookup } from 'mime-types'; +import { Context } from '../context'; import { AccessDeniedError, FileExistsError, FileLimitExceededError, FileUploadError, NotFoundError, ValidationError, @@ -132,7 +133,7 @@ export class SwitchAccountHandler extends Handler { } } -export async function apply(ctx) { +export async function apply(ctx: Context) { ctx.Route('switch_language', '/language/:lang', SwitchLanguageHandler); ctx.Route('home_files', '/file', FilesHandler); ctx.Route('fs_download', '/file/:uid/:filename', FSDownloadHandler); diff --git a/packages/hydrooj/src/lib/i18n.ts b/packages/hydrooj/src/lib/i18n.ts index eb1ae1f20..ed1da6fd9 100644 --- a/packages/hydrooj/src/lib/i18n.ts +++ b/packages/hydrooj/src/lib/i18n.ts @@ -19,10 +19,12 @@ class I18nService extends Service { } load(lang: string, content: Record) { - translations[lang] ||= []; - translations[lang].unshift(content); - this[Context.current]?.on('dispose', () => { - translations[lang] = translations[lang].filter((i) => i !== content); + this.ctx.effect(() => { + translations[lang] ||= []; + translations[lang].unshift(content); + return () => { + translations[lang] = translations[lang].filter((i) => i !== content); + }; }); } diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index 2d66fde0f..1b27808c9 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -301,8 +301,10 @@ declare module 'cordis' { const T = any>(origFunc: F, disposeFunc?) => function method(this: cordis.Service, ...args: Parameters) { - const res = origFunc(...args); - this[Context.current]?.on('dispose', () => (disposeFunc ? disposeFunc(res) : res())); + this.ctx.effect(() => { + const res = origFunc(...args); + return () => (disposeFunc ? disposeFunc(res) : res()); + }); }; export class SettingService extends Service { @@ -316,7 +318,7 @@ export class SettingService extends Service { } get(key: string) { - return (this[Context.current] ? this[Context.current].domain?.config?.[key.replace(/\./g, '$')] : null) ?? global.Hydro.model.system.get(key); + return (this.ctx ? this.ctx.domain?.config?.[key.replace(/\./g, '$')] : null) ?? global.Hydro.model.system.get(key); } } diff --git a/packages/hydrooj/src/service/check.ts b/packages/hydrooj/src/service/check.ts index 8307c4763..ad4ec1dd2 100644 --- a/packages/hydrooj/src/service/check.ts +++ b/packages/hydrooj/src/service/check.ts @@ -13,9 +13,11 @@ export class CheckService extends Service { checkers: Dictionary = {}; c = {}; addChecker(type: string, checkFunc: CheckItem) { - this.checkers[`check${type}`] = checkFunc; - this[Context.current]?.on('dispose', () => { - delete this.checkers[`check${type}`]; + this.ctx.effect(() => { + this.checkers[`check${type}`] = checkFunc; + return () => { + delete this.checkers[`check${type}`]; + }; }); } diff --git a/packages/hydrooj/src/service/worker.ts b/packages/hydrooj/src/service/worker.ts index 3b6e79ac3..9c1a2b70f 100644 --- a/packages/hydrooj/src/service/worker.ts +++ b/packages/hydrooj/src/service/worker.ts @@ -72,9 +72,11 @@ export class WorkerService extends Service { } public addHandler(type: string, handler: Function) { - this.handlers[type] = handler; - this[Context.current]?.on('dispose', () => { - delete this.handlers[type]; + this.ctx.effect(() => { + this.handlers[type] = handler; + return () => { + delete this.handlers[type]; + }; }); } diff --git a/packages/vjudge/src/index.ts b/packages/vjudge/src/index.ts index bf71ea708..e38e1f9c0 100644 --- a/packages/vjudge/src/index.ts +++ b/packages/vjudge/src/index.ts @@ -194,9 +194,7 @@ class VJudgeService extends Service { } // FIXME: potential race condition if (provider.Langs) this.updateLangs(type, provider.Langs); - this[Context.current]?.on('dispose', () => { - // TODO dispose session - }); + // TODO dispose session } async updateLangs(provider: string, mapping: Record>) {