core: drop global.Hydro.lib

This commit is contained in:
undefined committed 2025-03-10 12:31:25 +08:00
1 parent 1165bfff5b
commit 6ff66f2efc
17 files changed
+31 -45

No files matched your search

+12 -7
View File
@@ -113,7 +113,6 @@ Hydro 用户群:1085853538
## Unreleased ## Unreleased
- judge: breaking: 不再支持在 checker 等的编译阶段读取选手代码
- judge: 添加 checker 编译缓存 - judge: 添加 checker 编译缓存
- ui: 优化题目详情页面 OGP 信息 - ui: 优化题目详情页面 OGP 信息
- core&ui: 升级 simplewebauthn - core&ui: 升级 simplewebauthn
@@ -123,19 +122,25 @@ Hydro 用户群:1085853538
- ui&judge: 添加栈空间回显 - ui&judge: 添加栈空间回显
- install: 在树莓派中自动启用 cgroup.memory - install: 在树莓派中自动启用 cgroup.memory
- install: 添加 shm 空间大小警告 - install: 添加 shm 空间大小警告
- vjudge: 使用 vjudge.mount 表替代 domain.mount
- core: 升级到 cordis@4 - core: 升级到 cordis@4
- framework: 支持同时启用多个 renderer - framework: 支持同时启用多个 renderer
- core: 分离 HMR 和 Watcher 组件 - core: 分离 HMR 和 Watcher 组件
- core: i18n: 添加 interface 选项 - core: i18n: 添加 interface 选项
- judge: 添加 kattis checker 支持 - judge: 添加 kattis checker 支持
- core: 移除旧版本 bus 调用
- migrate: 修复 hustoj 自动运行 - migrate: 修复 hustoj 自动运行
- core: 强制要求使用 inject 声明插件依赖
- core: 移除 global.Hydro.service.db
- core: 移除 global.Hydro.service.service
- core: 移除 global.Hydro.service.storage
- core: Settings: 支持使用 Schemastery - core: Settings: 支持使用 Schemastery
- ui: 更新系统设置页面样式
- import-qduoj: 修复 spj=null
### Breaking API Changes
- vjudge: 使用 vjudge.mount 表替代 domain.mount
- judge: breaking: 不再支持在 checker 等的编译阶段读取选手代码
- core: 强制要求使用 inject 声明插件依赖
- core: 移除旧版本 bus 调用
- core: 移除 global.Hydro.service
- core: 移除 global.Hydro.ui.template
- core: 移除 global.Hydro.lib
## Hydro 4.19.0 / UI 4.57.0 ## Hydro 4.19.0 / UI 4.57.0
+3 -2
View File
@@ -19,7 +19,7 @@ const processDocument = (doc: Partial<ProblemDoc>) => {
return _.omit(doc, indexOmit); return _.omit(doc, indexOmit);
}; };
global.Hydro.lib.problemSearch = async (domainId, q, opts) => { async function problemSearch(domainId, q, opts) {
const allowedSize = SystemModel.get('elasic-search.indexSize') || 10000; const allowedSize = SystemModel.get('elasic-search.indexSize') || 10000;
const size = opts?.limit || SystemModel.get('pagination.problem'); const size = opts?.limit || SystemModel.get('pagination.problem');
const from = Math.min(allowedSize - size, opts?.skip || 0); const from = Math.min(allowedSize - size, opts?.skip || 0);
@@ -56,7 +56,7 @@ global.Hydro.lib.problemSearch = async (domainId, q, opts) => {
total: typeof res.hits.total === 'number' ? res.hits.total : res.hits.total.value, total: typeof res.hits.total === 'number' ? res.hits.total : res.hits.total.value,
hits: Array.from(new Set(hits)), hits: Array.from(new Set(hits)),
}; };
}; }
async function run({ domainId }, report) { async function run({ domainId }, report) {
try { try {
@@ -109,4 +109,5 @@ export const apply = (ctx: Context) => {
}), }),
run, run,
); );
ctx.provideModule('problemSearch', 'elastic', problemSearch);
}; };
+1 -1
View File
@@ -109,7 +109,7 @@ export class ProblemMainHandler extends Handler {
// eslint-disable-next-line @typescript-eslint/no-shadow // eslint-disable-next-line @typescript-eslint/no-shadow
const query = this.queryContext.query; const query = this.queryContext.query;
const psdict = {}; const psdict = {};
const search = global.Hydro.lib.problemSearch || defaultSearch; const search = Object.values(global.Hydro.module.problemSearch)[0] || defaultSearch;
const parsed = parser.parse(q, { const parsed = parser.parse(q, {
keywords: ['category', 'difficulty', 'namespace'], keywords: ['category', 'difficulty', 'namespace'],
offsets: false, offsets: false,
-2
View File
@@ -11,8 +11,6 @@ if (!global.Hydro) {
// @ts-ignore // @ts-ignore
model: {}, model: {},
script: {}, script: {},
// @ts-ignore
lib: {},
module: new Proxy({} as any, { module: new Proxy({} as any, {
get(self, key) { get(self, key) {
self[key] ||= {}; self[key] ||= {};
+1 -10
View File
@@ -613,15 +613,6 @@ export interface ProblemSearchOptions {
export type ProblemSearch = (domainId: string, q: string, options?: ProblemSearchOptions) => Promise<ProblemSearchResponse>; export type ProblemSearch = (domainId: string, q: string, options?: ProblemSearchOptions) => Promise<ProblemSearchResponse>;
export interface Lib extends Record<string, any> {
difficulty: typeof import('./lib/difficulty').default;
buildContent: typeof import('./lib/content').buildContent;
mail: typeof import('./lib/mail');
rating: typeof import('./lib/rating').default;
testdataConfig: typeof import('./lib/testdataConfig');
problemSearch: ProblemSearch;
}
export type UIInjectableFields = 'ProblemAdd' | 'Notification' | 'Nav' | 'UserDropdown' | 'DomainManage' | 'ControlPanel'; export type UIInjectableFields = 'ProblemAdd' | 'Notification' | 'Nav' | 'UserDropdown' | 'DomainManage' | 'ControlPanel';
export interface UI { export interface UI {
nodes: Record<UIInjectableFields, any[]>, nodes: Record<UIInjectableFields, any[]>,
@@ -638,13 +629,13 @@ export interface ModuleInterfaces {
lockUsername?: boolean; lockUsername?: boolean;
}; };
hash: (password: string, salt: string, user: User) => boolean | string | Promise<string>; hash: (password: string, salt: string, user: User) => boolean | string | Promise<string>;
problemSearch: ProblemSearch;
} }
export interface HydroGlobal { export interface HydroGlobal {
version: Record<string, string>; version: Record<string, string>;
model: Model; model: Model;
script: Record<string, Script>; script: Record<string, Script>;
lib: Lib;
module: { [K in keyof ModuleInterfaces]: Record<string, ModuleInterfaces[K]> }; module: { [K in keyof ModuleInterfaces]: Record<string, ModuleInterfaces[K]> };
ui: UI; ui: UI;
error: typeof import('./error'); error: typeof import('./error');
-1
View File
@@ -34,4 +34,3 @@ export function validate(input: string) {
} }
export default avatar; export default avatar;
global.Hydro.lib.avatar = avatar;
-2
View File
@@ -76,5 +76,3 @@ export function buildContent(source: ProblemSource, type: 'markdown' | 'html' =
...source.source ? [`## ${_('Source')}`, '', source.source, ''] : [], ...source.source ? [`## ${_('Source')}`, '', source.source, ''] : [],
].join('\n'); ].join('\n');
} }
global.Hydro.lib.buildContent = buildContent;
-1
View File
@@ -43,4 +43,3 @@ function difficultyAlgorithm(nSubmit: number, nAccept: number) {
} }
export default difficultyAlgorithm; export default difficultyAlgorithm;
global.Hydro.lib.difficulty = difficultyAlgorithm;
-4
View File
@@ -37,7 +37,3 @@ export async function sendMail(to: string, subject: string, text: string, html:
} }
return t; return t;
} }
global.Hydro.lib.mail = {
sendMail,
};
-2
View File
@@ -119,5 +119,3 @@ function calculate(users: RatingInputUser[]): RatingOutputUser[] {
} }
export default calculate; export default calculate;
global.Hydro.lib.rating = calculate;
@@ -37,5 +37,3 @@ export async function parseConfig(config: string | ProblemConfigFile = {}) {
if (cfg.filename && result.type === 'default') result.subType = cfg.filename; if (cfg.filename && result.type === 'default') result.subType = cfg.filename;
return result; return result;
} }
global.Hydro.lib.testdataConfig = { parseConfig };
+2
View File
@@ -44,6 +44,8 @@ export { default as mime } from './lib/mime';
export { default as difficultyAlgorithm } from './lib/difficulty'; export { default as difficultyAlgorithm } from './lib/difficulty';
export { default as rating } from './lib/rating'; export { default as rating } from './lib/rating';
export { default as avatar } from './lib/avatar'; export { default as avatar } from './lib/avatar';
export { parseConfig as testdataConfig } from './lib/testdataConfig';
export { sendMail } from './lib/mail';
/** @deprecated use Handler.paginate instead */ /** @deprecated use Handler.paginate instead */
export const paginate = db.paginate.bind(db); export const paginate = db.paginate.bind(db);
/** @deprecated use db.ranked instead */ /** @deprecated use db.ranked instead */
+7 -5
View File
@@ -144,7 +144,7 @@ export default class HMR extends Service {
} }
} }
private triggerLocalReload() { private async triggerLocalReload() {
this.analyzeChanges(); this.analyzeChanges();
/** plugins pending classification */ /** plugins pending classification */
@@ -207,10 +207,11 @@ export default class HMR extends Service {
return rollback(); return rollback();
} }
const reload = (plugin: any, runtime?: Plugin.Runtime) => { const reload = async (plugin: any, runtime?: Plugin.Runtime) => {
if (!runtime) return; if (!runtime) return;
for (const oldFiber of runtime.scopes) { for (const oldFiber of runtime.scopes) {
oldFiber.parent.plugin(plugin, oldFiber.config); // eslint-disable-next-line no-await-in-loop
await oldFiber.parent.plugin(plugin, oldFiber.config);
} }
}; };
@@ -226,7 +227,8 @@ export default class HMR extends Service {
} }
try { try {
reload(attempts[filename], runtime); // eslint-disable-next-line no-await-in-loop
await reload(attempts[filename], runtime);
logger.info('reload plugin at %c', path); logger.info('reload plugin at %c', path);
} catch (err) { } catch (err) {
logger.warn('failed to reload plugin at %c', path); logger.warn('failed to reload plugin at %c', path);
@@ -240,7 +242,7 @@ export default class HMR extends Service {
for (const [plugin, { filename, runtime }] of reloads) { for (const [plugin, { filename, runtime }] of reloads) {
try { try {
this.ctx.registry.delete(attempts[filename]); this.ctx.registry.delete(attempts[filename]);
reload(plugin, runtime); await reload(plugin, runtime);
} catch (err) { } catch (err) {
logger.warn(err); logger.warn(err);
} }
+2 -2
View File
@@ -10,7 +10,7 @@ export const inject = { 'sonic': { required: false } };
export function apply(ctx: Context) { export function apply(ctx: Context) {
ctx.plugin(SonicService); ctx.plugin(SonicService);
global.Hydro.lib.problemSearch = async (domainId, query, opts) => { ctx.provideModule('problemSearch', 'sonic', async (domainId, query, opts) => {
const limit = opts?.limit || SystemModel.get('pagination.problem'); const limit = opts?.limit || SystemModel.get('pagination.problem');
let hits = await ctx.sonic.query('problem', `${domainId}@title`, query, { limit }); let hits = await ctx.sonic.query('problem', `${domainId}@title`, query, { limit });
if (!opts.skip) { if (!opts.skip) {
@@ -29,7 +29,7 @@ export function apply(ctx: Context) {
total: hits.length, total: hits.length,
hits, hits,
}; };
}; });
async function run({ domainId }, report) { async function run({ domainId }, report) {
if (domainId) await ctx.sonic.flushb('problem', domainId); if (domainId) await ctx.sonic.flushb('problem', domainId);
+2 -2
View File
@@ -3,7 +3,6 @@ import {
Context, fs, Handler, Logger, NotFoundError, param, SettingModel, sha1, Context, fs, Handler, Logger, NotFoundError, param, SettingModel, sha1,
size, SystemModel, Types, UiContextBase, size, SystemModel, Types, UiContextBase,
} from 'hydrooj'; } from 'hydrooj';
import { debounce } from 'lodash';
import { tmpdir } from 'os'; import { tmpdir } from 'os';
import { import {
basename, join, relative, resolve, basename, join, relative, resolve,
@@ -118,6 +117,7 @@ export async function buildUI() {
} }
for (const lang in global.Hydro.locales) { for (const lang in global.Hydro.locales) {
if (!/^[a-zA-Z_]+$/.test(lang)) continue; if (!/^[a-zA-Z_]+$/.test(lang)) continue;
if (!global.Hydro.locales[lang].__interface) continue;
const str = `window.LOCALES=${JSON.stringify(global.Hydro.locales[lang][Symbol.for('iterate')])};`; const str = `window.LOCALES=${JSON.stringify(global.Hydro.locales[lang][Symbol.for('iterate')])};`;
addFile(`lang-${lang}.js`, str); addFile(`lang-${lang}.js`, str);
} }
@@ -160,7 +160,7 @@ export async function apply(ctx: Context) {
ctx.Route('constant', '/lazy/:version/:name', UiConstantsHandler); ctx.Route('constant', '/lazy/:version/:name', UiConstantsHandler);
ctx.Route('constant', '/resource/:version/:name', UiConstantsHandler); ctx.Route('constant', '/resource/:version/:name', UiConstantsHandler);
ctx.on('app/started', buildUI); ctx.on('app/started', buildUI);
const debouncedBuildUI = debounce(buildUI, 2000, { trailing: true }); const debouncedBuildUI = ctx.debounce(buildUI, 2000);
const triggerHotUpdate = (path?: string) => { const triggerHotUpdate = (path?: string) => {
if (path && !path.includes('/ui-default/') && !path.includes('/public/') && !path.includes('/frontend/')) return; if (path && !path.includes('/ui-default/') && !path.includes('/public/') && !path.includes('/frontend/')) return;
debouncedBuildUI(); debouncedBuildUI();
+1 -1
View File
@@ -59,6 +59,6 @@ function renderInline(text) {
return md.renderInline(text); return md.renderInline(text);
} }
global.Hydro.lib.markdown = module.exports = { module.exports = {
md, plugin, render, renderInline, md, plugin, render, renderInline,
}; };
@@ -133,7 +133,6 @@ class Nunjucks extends nunjucks.Environment {
this.addGlobal('utils', { status }); this.addGlobal('utils', { status });
this.addGlobal('avatarUrl', avatar); this.addGlobal('avatarUrl', avatar);
this.addGlobal('formatSeconds', misc.formatSeconds); this.addGlobal('formatSeconds', misc.formatSeconds);
this.addGlobal('lib', global.Hydro.lib);
this.addGlobal('model', global.Hydro.model); this.addGlobal('model', global.Hydro.model);
this.addGlobal('ui', global.Hydro.ui); this.addGlobal('ui', global.Hydro.ui);
this.addGlobal('isIE', (str) => { this.addGlobal('isIE', (str) => {