From c7117ef3ea00e99f9f5dc1d2c7e91acdbe1db833 Mon Sep 17 00:00:00 2001 From: undefined Date: Sun, 8 Jun 2025 21:42:03 +0800 Subject: [PATCH] core: rename ConfigService to SettingService --- packages/hydrooj/src/entry/cli.ts | 8 ++--- packages/hydrooj/src/entry/worker.ts | 6 ++-- packages/hydrooj/src/handler/contest.ts | 2 +- packages/hydrooj/src/handler/domain.ts | 2 +- packages/hydrooj/src/handler/homework.ts | 2 +- packages/hydrooj/src/handler/manage.ts | 16 +++++----- packages/hydrooj/src/handler/problem.ts | 2 +- packages/hydrooj/src/handler/user.ts | 2 +- packages/hydrooj/src/loader.ts | 6 ++-- packages/hydrooj/src/model/setting.ts | 34 +------------------- packages/hydrooj/src/service/server.ts | 2 +- packages/hydrooj/src/service/storage.ts | 2 +- packages/hydrooj/src/settings.ts | 40 ++++++++++++++++++------ packages/hydrooj/src/upgrade.ts | 2 +- packages/ui-default/index.ts | 2 +- 15 files changed, 59 insertions(+), 69 deletions(-) diff --git a/packages/hydrooj/src/entry/cli.ts b/packages/hydrooj/src/entry/cli.ts index 97f67caa1..5f5c11fb6 100644 --- a/packages/hydrooj/src/entry/cli.ts +++ b/packages/hydrooj/src/entry/cli.ts @@ -6,7 +6,7 @@ import { ObjectId } from 'mongodb'; import { Context } from '../context'; import { load as loadOptions } from '../options'; import { MongoService } from '../service/db'; -import { ConfigService } from '../settings'; +import { SettingService } from '../settings'; import { addon, builtinModel, model, service, } from './common'; @@ -110,10 +110,10 @@ export async function load(ctx: Context) { const pending = global.addons; const fail = []; await ctx.plugin(MongoService, loadOptions() || {}); - await ctx.plugin(ConfigService); + await ctx.plugin(SettingService); await require('../model/system').runConfig(); ctx = await new Promise((resolve) => { - ctx.inject(['loader', 'config', 'db'], (c) => { + ctx.inject(['loader', 'setting', 'db'], (c) => { resolve(c); }); }); @@ -127,7 +127,7 @@ export async function load(ctx: Context) { await builtinModel(ctx); await model(pending, fail, ctx); ctx = await new Promise((resolve) => { - ctx.inject(['server', 'setting', 'worker'], (c) => { + ctx.inject(['server', 'worker'], (c) => { resolve(c); }); }); diff --git a/packages/hydrooj/src/entry/worker.ts b/packages/hydrooj/src/entry/worker.ts index 20bc8f856..85e304293 100644 --- a/packages/hydrooj/src/entry/worker.ts +++ b/packages/hydrooj/src/entry/worker.ts @@ -7,7 +7,7 @@ import { Context } from '../context'; import { Logger } from '../logger'; import { load } from '../options'; import { MongoService } from '../service/db'; -import { ConfigService } from '../settings'; +import { SettingService } from '../settings'; import { addon, builtinModel, locale, model, service, } from './common'; @@ -30,11 +30,11 @@ export async function apply(ctx: Context) { const fail = []; await locale(pending, fail); await ctx.plugin(MongoService, load() || {}); - await ctx.plugin(ConfigService); + await ctx.plugin(SettingService); const modelSystem = require('../model/system'); await modelSystem.runConfig(); ctx = await new Promise((resolve) => { - ctx.inject(['loader', 'config', 'db'], (c) => { + ctx.inject(['loader', 'setting', 'db'], (c) => { resolve(c); }); }); diff --git a/packages/hydrooj/src/handler/contest.ts b/packages/hydrooj/src/handler/contest.ts index a6edb2199..e86ae68c2 100644 --- a/packages/hydrooj/src/handler/contest.ts +++ b/packages/hydrooj/src/handler/contest.ts @@ -743,7 +743,7 @@ export async function apply(ctx: Context) { await Promise.all(tasks); }); ctx.plugin(ScoreboardService); - ctx.inject(['scoreboard'], ({ Route, scoreboard }) => { + await ctx.inject(['scoreboard'], ({ Route, scoreboard }) => { Route('contest_scoreboard', '/contest/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD); Route('contest_scoreboard_view', '/contest/:tid/scoreboard/:view', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD); scoreboard.addView('default', 'Default', { tdoc: 'tdoc', groups: 'groups', realtime: Types.Boolean }, { diff --git a/packages/hydrooj/src/handler/domain.ts b/packages/hydrooj/src/handler/domain.ts index d6f6ec27d..aae0826d9 100644 --- a/packages/hydrooj/src/handler/domain.ts +++ b/packages/hydrooj/src/handler/domain.ts @@ -461,7 +461,7 @@ export async function apply(ctx: Context) { ctx.Route('domain_join_applications', '/domain/join_applications', DomainJoinApplicationsHandler); ctx.Route('domain_join', '/domain/join', DomainJoinHandler, PRIV.PRIV_USER_PROFILE); ctx.Route('domain_search', '/domain/search', DomainSearchHandler, PRIV.PRIV_USER_PROFILE); - ctx.inject(['api'], ({ api }) => { + await ctx.inject(['api'], ({ api }) => { api.provide(DomainApi); }); } diff --git a/packages/hydrooj/src/handler/homework.ts b/packages/hydrooj/src/handler/homework.ts index 22fa78ee1..683b574a8 100644 --- a/packages/hydrooj/src/handler/homework.ts +++ b/packages/hydrooj/src/handler/homework.ts @@ -314,7 +314,7 @@ export async function apply(ctx) { ctx.Route('homework_edit', '/homework/:tid/edit', HomeworkEditHandler); ctx.Route('homework_files', '/homework/:tid/file', HomeworkFilesHandler, PERM.PERM_VIEW_HOMEWORK); ctx.Route('homework_file_download', '/homework/:tid/file/:filename', ContestFileDownloadHandler, PERM.PERM_VIEW_HOMEWORK); - ctx.inject(['scoreboard'], ({ Route }) => { + await ctx.inject(['scoreboard'], ({ Route }) => { Route('homework_scoreboard', '/homework/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_HOMEWORK_SCOREBOARD); Route('homework_scoreboard_view', '/homework/:tid/scoreboard/:view', ContestScoreboardHandler, PERM.PERM_VIEW_HOMEWORK_SCOREBOARD); }); diff --git a/packages/hydrooj/src/handler/manage.ts b/packages/hydrooj/src/handler/manage.ts index 8d6a71d20..107f05aef 100644 --- a/packages/hydrooj/src/handler/manage.ts +++ b/packages/hydrooj/src/handler/manage.ts @@ -199,14 +199,14 @@ class SystemConfigHandler extends SystemHandler { try { try { - value = Schema.intersect(this.ctx.config.settings)(yaml.load(this.ctx.config.configSource)); + value = Schema.intersect(this.ctx.setting.settings)(yaml.load(this.ctx.setting.configSource)); } catch (e) { - value = yaml.load(this.ctx.config.configSource); + value = yaml.load(this.ctx.setting.configSource); } - for (const schema of this.ctx.config.settings) processNode(value, schema); + for (const schema of this.ctx.setting.settings) processNode(value, schema); } catch (e) { } this.response.body = { - schema: Schema.intersect(this.ctx.config.settings).toJSON(), + schema: Schema.intersect(this.ctx.setting.settings).toJSON(), value: yaml.dump(value), }; } @@ -214,7 +214,7 @@ class SystemConfigHandler extends SystemHandler { @requireSudo @param('value', Types.String) async post({ }, value: string) { - const oldConfig = yaml.load(this.ctx.config.configSource); + const oldConfig = yaml.load(this.ctx.setting.configSource); let config; const processNode = (node: any, old: any, schema: Schema, parent?: any, accessKey?: string) => { if (['union', 'intersect'].includes(schema.type)) { @@ -231,11 +231,11 @@ class SystemConfigHandler extends SystemHandler { try { config = yaml.load(value); - for (const schema of this.ctx.config.settings) processNode(config, oldConfig, schema, null, ''); + for (const schema of this.ctx.setting.settings) processNode(config, oldConfig, schema, null, ''); } catch (e) { throw new ValidationError('value', '', e.message); } - await this.ctx.config.saveConfig(config); + await this.ctx.setting.saveConfig(config); } } @@ -357,7 +357,7 @@ class SystemUserPrivHandler extends SystemHandler { } } -export const inject = ['config', 'check']; +export const inject = ['setting', 'check']; export async function apply(ctx) { ctx.Route('manage', '/manage', SystemMainHandler); ctx.Route('manage_dashboard', '/manage/dashboard', SystemDashboardHandler); diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index 50cfc1dfc..379e50db0 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -1070,7 +1070,7 @@ export async function apply(ctx: Context) { ctx.Route('problem_solution_reply_raw', '/p/:pid/solution/:psid/:psrid/raw', ProblemSolutionRawHandler, PERM.PERM_VIEW_PROBLEM); ctx.Route('problem_statistics', '/p/:pid/stat', ProblemStatisticsHandler, PERM.PERM_VIEW_PROBLEM); ctx.Route('problem_create', '/problem/create', ProblemCreateHandler, PERM.PERM_CREATE_PROBLEM); - ctx.inject(['api'], ({ api }) => { + await ctx.inject(['api'], ({ api }) => { api.provide(ProblemApi); }); } diff --git a/packages/hydrooj/src/handler/user.ts b/packages/hydrooj/src/handler/user.ts index b91c154e9..3cda116fa 100644 --- a/packages/hydrooj/src/handler/user.ts +++ b/packages/hydrooj/src/handler/user.ts @@ -625,7 +625,7 @@ export async function apply(ctx: Context) { throw new NotFoundError(); }, }); - ctx.inject(['api'], ({ api }) => { + await ctx.inject(['api'], ({ api }) => { api.provide(UserApi); }); } diff --git a/packages/hydrooj/src/loader.ts b/packages/hydrooj/src/loader.ts index 6fcf3ba10..21d8cdebe 100644 --- a/packages/hydrooj/src/loader.ts +++ b/packages/hydrooj/src/loader.ts @@ -50,7 +50,7 @@ export class Loader extends Service { public cache: Record = Object.create(null); // public warnings: Record = Object.create(null); - static inject = ['config', 'timer', 'i18n', 'logger']; + static inject = ['setting', 'timer', 'i18n', 'logger']; constructor(ctx: Context) { super(ctx, 'loader'); @@ -100,8 +100,8 @@ export class Loader extends Service { const schemaRequest = configScope ? Schema.object({ [configScope]: schema, }) : schema; - await this.ctx.config._tryMigrateConfig(schemaRequest); - const res = this.ctx.config.requestConfig(schemaRequest); + await this.ctx.setting._tryMigrateConfig(schemaRequest); + const res = this.ctx.setting.requestConfig(schemaRequest); return configScope ? res[configScope] : res; } diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index 395526ab2..2161a4b91 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -1,14 +1,13 @@ /* eslint-disable max-len */ /* eslint-disable no-await-in-loop */ import fs from 'fs'; -import * as cordis from 'cordis'; import yaml from 'js-yaml'; import { Dictionary } from 'lodash'; import moment from 'moment-timezone'; import Schema from 'schemastery'; import { LangConfig, parseLang } from '@hydrooj/common'; import { findFileSync, retry } from '@hydrooj/utils'; -import { Context, Service } from '../context'; +import { Context } from '../context'; import { Setting as _Setting } from '../interface'; import { Logger } from '../logger'; import * as builtin from './builtin'; @@ -362,38 +361,8 @@ SystemSetting( export const langs: Record = {}; -declare module 'cordis' { - interface Context { - setting: SettingService; - } -} - -const T = any>(origFunc: F, disposeFunc?) => - function method(this: cordis.Service, ...args: Parameters) { - this.ctx.effect(() => { - const res = origFunc(...args); - return () => (disposeFunc ? disposeFunc(res) : res()); - }); - }; - -export class SettingService extends Service { - PreferenceSetting = T(PreferenceSetting); - AccountSetting = T(AccountSetting); - DomainSetting = T(DomainSetting); - DomainUserSetting = T(DomainUserSetting); - SystemSetting = T(SystemSetting); - constructor(ctx: Context) { - super(ctx, 'setting'); - } - - get(key: string) { - return (this.ctx ? this.ctx.domain?.config?.[key.replace(/\./g, '$')] : null) ?? global.Hydro.model.system.get(key); - } -} - export const inject = ['db']; export async function apply(ctx: Context) { - ctx.plugin(SettingService); logger.info('Ensuring settings'); const system = global.Hydro.model.system; for (const setting of SYSTEM_SETTINGS) { @@ -424,7 +393,6 @@ global.Hydro.model.setting = { apply, inject, - SettingService, Setting, PreferenceSetting, AccountSetting, diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index 2daa908d0..089ca369a 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -91,7 +91,7 @@ export async function apply(ctx: Context) { xhost: system.get('server.xhost'), }); if (process.env.HYDRO_CLI) return; - ctx.inject(['server', 'oauth', 'setting'], (childContext) => { + await ctx.inject(['server', 'oauth', 'setting'], (childContext) => { const { server, on, oauth } = childContext; server.addHandlerLayer('init', async (c, next) => { const init = Date.now(); diff --git a/packages/hydrooj/src/service/storage.ts b/packages/hydrooj/src/service/storage.ts index ec62738d6..582667c8d 100644 --- a/packages/hydrooj/src/service/storage.ts +++ b/packages/hydrooj/src/service/storage.ts @@ -400,7 +400,7 @@ export async function apply(ctx: Context, config: ReturnType service = new LocalStorageService(config); } await service.start(); - ctx.inject(['server'], ({ server }) => { + await ctx.inject(['server'], ({ server }) => { let endpoint = config.endPoint; if (config.type === 's3' && !config.pathStyle) { try { diff --git a/packages/hydrooj/src/settings.ts b/packages/hydrooj/src/settings.ts index 638e588fc..16ea82e63 100644 --- a/packages/hydrooj/src/settings.ts +++ b/packages/hydrooj/src/settings.ts @@ -2,18 +2,29 @@ import yaml from 'js-yaml'; import Schema from 'schemastery'; import { Context, Service } from './context'; import { Logger } from './logger'; +import { + AccountSetting, DomainSetting, DomainUserSetting, PreferenceSetting, SystemSetting, +} from './model/setting'; const logger = new Logger('settings'); -declare module './context' { +declare module 'cordis' { interface Context { - config: ConfigService; + setting: SettingService; } } -export class ConfigService extends Service { +const T = any>(origFunc: F, disposeFunc?) => + function method(this: Service, ...args: Parameters) { + this.ctx.effect(() => { + const res = origFunc(...args); + return () => (disposeFunc ? disposeFunc(res) : res()); + }); + }; + +export class SettingService extends Service { static inject = ['db']; - static name = 'config'; + static name = 'setting'; static blacklist = ['__proto__', 'prototype', 'constructor']; settings: Schema[] = []; @@ -23,8 +34,14 @@ export class ConfigService extends Service { private initialValues = {}; private _lastMigrate = Promise.resolve(); + PreferenceSetting = T(PreferenceSetting); + AccountSetting = T(AccountSetting); + DomainSetting = T(DomainSetting); + DomainUserSetting = T(DomainUserSetting); + SystemSetting = T(SystemSetting); + constructor(ctx: Context) { - super(ctx, 'config'); + super(ctx, 'setting'); } async [Context.init]() { @@ -54,7 +71,7 @@ export class ConfigService extends Service { applyDelta(source: any, key: string, value: any) { const path = key.split('.'); - if (path.some((i) => ConfigService.blacklist.includes(i))) return false; + if (path.some((i) => SettingService.blacklist.includes(i))) return false; const t = path.pop(); const root = JSON.parse(JSON.stringify(source)); let cursor = root; @@ -111,9 +128,9 @@ export class ConfigService extends Service { await this._lastMigrate; } - get(key: string) { + _get(key: string) { const parts = key.split('.'); - if (parts.some((p) => ConfigService.blacklist.includes(p.toString()))) throw new Error('Invalid path'); + if (parts.some((p) => SettingService.blacklist.includes(p.toString()))) throw new Error('Invalid path'); let currentValue = this.applied; for (const p of parts) { if (!currentValue) return undefined; @@ -122,6 +139,11 @@ export class ConfigService extends Service { return currentValue; } + get(key: string) { + return (this.ctx ? this.ctx.domain?.config?.[key.replace(/\./g, '$')] : null) + ?? (this._get(key) || global.Hydro?.model?.system?.get?.(key)); + } + async setConfig(key: string, value: any) { const newConfig = this.applyDelta(this.systemConfig, key, value); await this.saveConfig(newConfig); @@ -150,7 +172,7 @@ export class ConfigService extends Service { }); const that = this; const getAccess = (path: (string | symbol)[]) => { - if (path.some((p) => ConfigService.blacklist.includes(p.toString()))) throw new Error('Invalid path'); + if (path.some((p) => SettingService.blacklist.includes(p.toString()))) throw new Error('Invalid path'); let currentValue = curValue; for (const p of path) { currentValue = currentValue[p]; diff --git a/packages/hydrooj/src/upgrade.ts b/packages/hydrooj/src/upgrade.ts index 6317423c2..e3abafa1c 100644 --- a/packages/hydrooj/src/upgrade.ts +++ b/packages/hydrooj/src/upgrade.ts @@ -290,7 +290,7 @@ export const coreScripts: MigrationScript[] = [ 'file.pathStyle', 'file.endPointForUser', 'file.endPointForJudge', ] as any[]) as any; if ((endPoint && accessKey) || process.env.MINIO_ACCESS_KEY) { - await app.get('config').setConfig('file', { + await app.get('setting').setConfig('file', { type: 's3', endPoint: process.env.MINIO_ACCESS_KEY ? 'http://127.0.0.1:9000/' : endPoint, accessKey: process.env.MINIO_ACCESS_KEY || accessKey, diff --git a/packages/ui-default/index.ts b/packages/ui-default/index.ts index aa1a35c82..3eff2918c 100644 --- a/packages/ui-default/index.ts +++ b/packages/ui-default/index.ts @@ -76,7 +76,7 @@ class MarkdownHandler extends Handler { class SystemConfigSchemaHandler extends Handler { async get() { - const schema = convert(Schema.intersect(this.ctx.config.settings) as any, true); + const schema = convert(Schema.intersect(this.ctx.setting.settings) as any, true); this.response.body = schema; } }