diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index b264abdf5..7391f0abf 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -1,7 +1,7 @@ { "name": "@hydrooj/hydrojudge", "bin": "bin/hydrojudge.js", - "version": "2.12.17", + "version": "2.13.0", "main": "package.json", "author": "undefined ", "repository": "https://github.com/hydro-dev/Hydro.git", diff --git a/packages/hydrojudge/src/check.ts b/packages/hydrojudge/src/check.ts index 67acf02de..14460cd60 100644 --- a/packages/hydrojudge/src/check.ts +++ b/packages/hydrojudge/src/check.ts @@ -3,36 +3,16 @@ import { findFileSync } from '@hydrooj/utils/lib/utils'; import checkers from './checkers'; import compile from './compile'; import { SystemError } from './error'; -import { Execute } from './interface'; -import { CopyInFile } from './sandbox/interface'; +import { CheckConfig, Execute } from './interface'; import { parseFilename } from './utils'; const testlibSrc = findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'); -interface CheckConfig { - checker_type: string; - stdin: CopyInFile, - stdout: CopyInFile, - user_stdout: CopyInFile, - user_stderr: CopyInFile, - copyIn?: Record, - score: number, - detail: boolean, -} - export async function check(config: CheckConfig): Promise<[number, number, string]> { if (!checkers[config.checker_type]) throw new SystemError('Unknown checker type {0}', [config.checker_type]); const { code, status, score, message, - } = await checkers[config.checker_type]({ - input: config.stdin, - output: config.stdout, - user_stdout: config.user_stdout, - user_stderr: config.user_stderr, - score: config.score, - copyIn: config.copyIn || {}, - detail: config.detail, - }); + } = await checkers[config.checker_type](config); if (code) throw new SystemError('Checker returned {0}.', [code]); return [status, score, message]; } diff --git a/packages/hydrojudge/src/checkers.ts b/packages/hydrojudge/src/checkers.ts index dbb0ad571..91c29402a 100644 --- a/packages/hydrojudge/src/checkers.ts +++ b/packages/hydrojudge/src/checkers.ts @@ -1,27 +1,10 @@ /* eslint-disable no-template-curly-in-string */ import { STATUS } from '@hydrooj/utils/lib/status'; import { SystemError } from './error'; +import { CheckConfig, CheckResult } from './interface'; import { run } from './sandbox'; -import { CopyInFile } from './sandbox/interface'; import { parse } from './testlib'; -interface CheckConfig { - input: CopyInFile, - output: CopyInFile, - user_stdout: CopyInFile, - user_stderr: CopyInFile, - copyIn: Record, - score: number, - detail: boolean, -} - -interface CheckResult { - status: number, - score: number, - message: string, - code?: number, -} - type Checker = (config: CheckConfig) => Promise; const checkers: Record = { @@ -129,6 +112,7 @@ const checkers: Record = { ...config.copyIn, }, copyOut: ['score', 'message'], + env: config.env, }); const { message } = files; const score = parseInt(files.score, 10); @@ -196,6 +180,7 @@ const checkers: Record = { answer: config.output, ...config.copyIn, }, + env: config.env, }); if (status === STATUS.STATUS_SYSTEM_ERROR) { return { diff --git a/packages/hydrojudge/src/hosts/hydro.ts b/packages/hydrojudge/src/hosts/hydro.ts index 13784927b..f61364414 100644 --- a/packages/hydrojudge/src/hosts/hydro.ts +++ b/packages/hydrojudge/src/hosts/hydro.ts @@ -38,6 +38,7 @@ class JudgeTask { data: any[]; folder: string; config: any; + env: Record; getLang: (name: string) => LangConfig; constructor(session: Hydro, request, ws: WebSocket) { @@ -63,6 +64,13 @@ class JudgeTask { this.source = this.request.source; this.tmpdir = path.resolve(getConfig('tmp_dir'), this.host, this.rid); this.clean = []; + this.env = { + HYDRO_DOMAIN: this.request.domainId.toString(), + HYDRO_RECORD: this.rid, + HYDRO_LANG: this.lang, + HYDRO_USER: this.request.uid.toString(), + HYDRO_CONTEST: this.request.tid?.toString() || '', + }; await Lock.acquire(`${this.host}/${this.source}/${this.rid}`); fs.ensureDirSync(this.tmpdir); tmpfs.mount(this.tmpdir, getConfig('tmpfs_size')); diff --git a/packages/hydrojudge/src/interface.ts b/packages/hydrojudge/src/interface.ts index 64cd54a09..1a9250cc3 100644 --- a/packages/hydrojudge/src/interface.ts +++ b/packages/hydrojudge/src/interface.ts @@ -1,12 +1,33 @@ import { CopyInFile } from './sandbox/interface'; + export interface Execute { execute: string, clean: Function, copyIn: Record, time?: number, } + export interface CompileErrorInfo { stdout?: string, stderr?: string, status?: number } + +export interface CheckConfig { + checker_type: string; + input: CopyInFile; + output: CopyInFile; + user_stdout: CopyInFile; + user_stderr: CopyInFile; + copyIn: Record; + score: number; + detail: boolean; + env?: Record; +} + +export interface CheckResult { + status: number, + score: number, + message: string, + code?: number, +} diff --git a/packages/hydrojudge/src/judge/default.ts b/packages/hydrojudge/src/judge/default.ts index d00c875f3..b8ac810e8 100644 --- a/packages/hydrojudge/src/judge/default.ts +++ b/packages/hydrojudge/src/judge/default.ts @@ -67,14 +67,15 @@ function judgeCase(c: Case, sid: string) { status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED; } else { [status, score, message] = await check({ - copyIn: ctx.checker.copyIn, - stdin: { src: c.input }, - stdout: { src: c.output }, + copyIn: ctx.checker.copyIn || {}, + input: { src: c.input }, + output: { src: c.output }, user_stdout: stdout, user_stderr: stderr, checker_type: ctx.config.checker_type, score: ctxSubtask.subtask.score, detail: ctx.config.detail ?? true, + env: ctx.env, }); } } else if (status === STATUS.STATUS_RUNTIME_ERROR && code) { diff --git a/packages/hydrojudge/src/judge/hack.ts b/packages/hydrojudge/src/judge/hack.ts index d93176f3e..680f72abf 100644 --- a/packages/hydrojudge/src/judge/hack.ts +++ b/packages/hydrojudge/src/judge/hack.ts @@ -97,8 +97,8 @@ export const judge = async (ctx: Context) => { } else { [status, , message] = await check({ copyIn: copyInDir(path.resolve(ctx.tmpdir, 'checker')), - stdin: { src: input }, - stdout: { src: stdout }, + input: { src: input }, + output: { src: stdout }, user_stdout: { src: stdout }, user_stderr: { src: stderr }, checker_type: ctx.config.checker_type, diff --git a/packages/hydrojudge/src/judge/interactive.ts b/packages/hydrojudge/src/judge/interactive.ts index b3fe19a12..7b128f7ec 100644 --- a/packages/hydrojudge/src/judge/interactive.ts +++ b/packages/hydrojudge/src/judge/interactive.ts @@ -35,6 +35,7 @@ function judgeCase(c: Case) { time: ctxSubtask.subtask.time * 2 * ctx.executeInteractor.time, memory: ctxSubtask.subtask.memory * 2, copyOut: ['/w/tout?'], + env: ctx.env, }, ); // TODO handle tout (maybe pass to checker?) diff --git a/packages/hydrojudge/src/judge/interface.ts b/packages/hydrojudge/src/judge/interface.ts index e1f54ee95..0e872cd8d 100644 --- a/packages/hydrojudge/src/judge/interface.ts +++ b/packages/hydrojudge/src/judge/interface.ts @@ -32,6 +32,7 @@ export interface JudgeTaskInterface { input?: string; clean: Function[]; config: Config; + env?: Record; } export interface RuntimeContext { diff --git a/packages/hydrojudge/src/sandbox.ts b/packages/hydrojudge/src/sandbox.ts index 70ae22366..26438c0c2 100644 --- a/packages/hydrojudge/src/sandbox.ts +++ b/packages/hydrojudge/src/sandbox.ts @@ -39,6 +39,7 @@ interface Parameter { copyOut?: string[]; copyOutCached?: string[]; cacheStdoutAndStderr?: boolean; + env?: Record; } interface SandboxAdaptedResult { @@ -72,6 +73,7 @@ function proc({ processLimit = getConfig('processLimit'), stdin = '', copyIn = {}, copyOut = [], copyOutCached = [], cacheStdoutAndStderr = false, + env = {}, }: Parameter = {}): Cmd { if (!supportOptional) { copyOut = (copyOut as string[]).map((i) => (i.endsWith('?') ? i.substr(0, i.length - 1) : i)); @@ -84,7 +86,7 @@ function proc({ } return { args: parseArgs(execute), - env: getConfig('env').split('\n'), + env: [...getConfig('env').split('\n'), ...Object.keys(env).map((i) => `${i}=${env[i].replace(/=/g, '\\=')}`)], files: [ stdin ? { src: stdin } : { content: '' }, { name: 'stdout', max: Math.floor(1024 * 1024 * size) }, diff --git a/packages/hydrojudge/src/service.ts b/packages/hydrojudge/src/service.ts index c34687c71..8f6d37a4e 100644 --- a/packages/hydrojudge/src/service.ts +++ b/packages/hydrojudge/src/service.ts @@ -150,6 +150,7 @@ async function postInit() { code: string; data: any[]; config: any; + env: any; input?: string; next: (data: any, id?: number) => void; end: (data: any) => void; @@ -176,6 +177,13 @@ async function postInit() { this.source = this.request.source; this.config = this.request.config; this.input = this.request.input; + this.env = { + HYDRO_DOMAIN: this.request.domainId.toString(), + HYDRO_RECORD: this.rid, + HYDRO_LANG: this.lang, + HYDRO_USER: this.request.uid.toString(), + HYDRO_CONTEST: this.request.tid?.toString() || '', + }; this.next = getNext(this); this.end = getEnd(this.rid); this.tmpdir = path.resolve(getConfig('tmp_dir'), this.rid);