diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index 462bec25e..cb7d201ad 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/hydrojudge", - "version": "2.0.12", + "version": "2.0.13", "main": "package.json", "author": "masnn", "os": [ @@ -30,4 +30,4 @@ "build": "tsc", "lint": "eslint . --ext ts --fix" } -} +} \ No newline at end of file diff --git a/packages/hydrojudge/src/cases.ts b/packages/hydrojudge/src/cases.ts index 9eb698507..2b8c1212a 100644 --- a/packages/hydrojudge/src/cases.ts +++ b/packages/hydrojudge/src/cases.ts @@ -4,7 +4,17 @@ import { Dictionary } from 'lodash'; import { FormatError, SystemError } from './error'; import { parseTimeMS, parseMemoryMB, ensureFile } from './utils'; -const RE0 = [ +interface Re0 { + reg: RegExp, + output: (a: RegExpExecArray) => string, + id: (a: RegExpExecArray) => number, +} + +interface Re1 extends Re0 { + subtask: (a: RegExpExecArray) => number, +} + +const RE0: Re0[] = [ { reg: /^([a-z+_\-A-Z]*)([0-9]+).in$/, output: (a) => `${a[1] + a[2]}.out`, @@ -25,8 +35,28 @@ const RE0 = [ output: (a) => `output${a[2]}.txt`, id: (a) => parseInt(a[2], 10), }, + { + reg: /^input\/([a-z+_\-A-Z]*)([0-9]+).in$/, + output: (a) => `output/${a[1] + a[2]}.out`, + id: (a) => parseInt(a[2], 10), + }, + { + reg: /^input\/([a-z+_\-A-Z]*)([0-9]+).in$/, + output: (a) => `output/${a[1] + a[2]}.ans`, + id: (a) => parseInt(a[2], 10), + }, + { + reg: /^input\/([a-z+_\-A-Z0-9]*)\.in([0-9]+)$/, + output: (a) => `output/${a[1]}.ou${a[2]}`, + id: (a) => parseInt(a[2], 10), + }, + { + reg: /^input\/(input)([0-9]+).txt$/, + output: (a) => `output/output${a[2]}.txt`, + id: (a) => parseInt(a[2], 10), + }, ]; -const RE1 = [ +const RE1: Re1[] = [ { reg: /^([a-z+_\-A-Z]*)([0-9]+)-([0-9]+).in$/, output: (a) => `${a[1] + a[2]}-${a[3]}.out`, @@ -35,7 +65,7 @@ const RE1 = [ }, ]; -async function read0(folder, files, checkFile) { +async function read0(folder: string, files: string[], checkFile) { const cases = []; for (const file of files) { for (const REG of RE0) { @@ -89,7 +119,7 @@ async function read0(folder, files, checkFile) { return config; } -async function read1(folder, files, checkFile) { +async function read1(folder: string, files: string[], checkFile) { const subtask = {}; const subtasks = []; for (const file of files) { @@ -144,6 +174,14 @@ async function readAutoCases(folder, { next }) { const checkFile = ensureFile(folder); try { const files = await fs.readdir(folder); + if (await fs.pathExists(path.resolve(folder, 'input'))) { + const inputs = await fs.readdir(path.resolve(folder, 'input')); + files.push(...inputs.map((i) => `input/${i}`)); + } + if (await fs.pathExists(path.resolve(folder, 'output'))) { + const outputs = await fs.readdir(path.resolve(folder, 'output')); + files.push(...outputs.map((i) => `output/${i}`)); + } let result = await read0(folder, files, checkFile); if (!result.count) result = await read1(folder, files, checkFile); Object.assign(config, result); diff --git a/packages/hydrojudge/src/judge/default.ts b/packages/hydrojudge/src/judge/default.ts index 95cd97f3e..f804e93dc 100644 --- a/packages/hydrojudge/src/judge/default.ts +++ b/packages/hydrojudge/src/judge/default.ts @@ -3,7 +3,7 @@ import path from 'path'; import fs from 'fs-extra'; import { argv } from 'yargs'; import { STATUS } from 'hydrooj/dist/model/builtin'; -import { CompileError } from '../error'; +import { CompileError, SystemError } from '../error'; import { copyInDir, parseFilename } from '../utils'; import { run } from '../sandbox'; import compile from '../compile'; @@ -106,6 +106,7 @@ function judgeSubtask(subtask) { } export const judge = async (ctx) => { + if (!ctx.config.subtasks.length) throw new SystemError('没有找到测试数据'); if (ctx.config.template) { if (ctx.config.template[ctx.lang]) { const tpl = ctx.config.template[ctx.lang]; diff --git a/packages/hydrojudge/src/service.ts b/packages/hydrojudge/src/service.ts index aa693ea58..33632b1af 100644 --- a/packages/hydrojudge/src/service.ts +++ b/packages/hydrojudge/src/service.ts @@ -28,6 +28,8 @@ async function postInit() { const { problem, file, task } = global.Hydro.model; const _judge = global.Hydro.handler.judge as any; const { monitor } = global.Hydro.service; + const { Logger } = global.Hydro.Logger; + const logger = new Logger('judge'); const info = await sysinfo.get(); monitor.updateJudger(info); @@ -85,7 +87,7 @@ async function postInit() { async function cacheOpen(domainId: string, pid: string, version: string) { const filePath = path.join(homedir(), '.cache', 'hydro', 'judge', domainId, pid); - console.log(filePath); + logger.debug('Cache found at %s', filePath); if (fs.existsSync(filePath)) { let ver: string; try { @@ -103,7 +105,8 @@ async function postInit() { function getNext(that) { that.nextId = 1; that.nextWaiting = []; - return (data, id) => { + return (data, id = 0) => { + logger.debug('Next: %d %o', id, data); data.domainId = that.domainId; data.rid = new ObjectID(that.rid); data.time = data.time_ms || data.time; @@ -143,14 +146,9 @@ async function postInit() { data.key = 'end'; data.rid = new ObjectID(rid); data.domainId = domainId; - data.time = data.time_ms || data.time; - data.memory = data.memory_kb || data.memory; - console.log({ - status: data.status, - score: data.score, - time_ms: data.time_ms, - memory_kb: data.memory_kb, - }); + data.time = data.time_ms ?? data.time; + data.memory = data.memory_kb ?? data.memory; + logger.info('End: status=%d score=%d time=%dms memory=%dkb', data.status, data.score, data.time, data.memory); _judge.end(data); }; } @@ -176,7 +174,7 @@ async function postInit() { config: any; - next: (data: any, id?: any) => void; + next: (data: any, id?: number) => void; end: (data: any) => void; @@ -208,7 +206,7 @@ async function postInit() { this.clean = []; fs.ensureDirSync(this.tmpdir); tmpfs.mount(this.tmpdir, '64m'); - console.log(`Submission: ${this.rid}`, { pid: this.pid }); + logger.info(`Submission: ${this.rid}`, { pid: this.pid }); if (this.config.input) await this.run(); else if (this.config.hack) await this.hack(); else await this.submission(); @@ -224,7 +222,7 @@ async function postInit() { status: STATUS_SYSTEM_ERROR, score: 0, time_ms: 0, memory_kb: 0, }); } else { - console.error(e); + logger.error(e); this.next({ message: `${e.message}\n${e.stack}\n${JSON.stringify(e.params)}` }); this.end({ status: STATUS_SYSTEM_ERROR, score: 0, time_ms: 0, memory_kb: 0, @@ -269,7 +267,7 @@ async function postInit() { } } - task.consume({ type: 'judge' }, (t) => (new JudgeTask(t)).handle().catch(console.error)); + task.consume({ type: 'judge' }, (t) => (new JudgeTask(t)).handle().catch(logger.error)); } global.Hydro.service.bus.once('app/started', postInit); diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index f8da64d11..41ad48ee1 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.13.20", + "version": "2.13.21", "bin": "bin/hydrooj.js", "main": "dist/loader.js", "typings": "dist/loader.d.ts", diff --git a/packages/hydrooj/src/handler/judge.ts b/packages/hydrooj/src/handler/judge.ts index be2a5d19d..f28b09625 100644 --- a/packages/hydrooj/src/handler/judge.ts +++ b/packages/hydrooj/src/handler/judge.ts @@ -57,10 +57,10 @@ export async function next(body: JudgeResultBody) { $push.compilerTexts = body.compilerText; } if (body.status) $set.status = body.status; - if (body.score) $set.score = body.score; - if (body.time) $set.time = body.time; - if (body.memory) $set.memory = body.memory; - if (body.progress) $set.progress = body.progress; + if (body.score !== undefined) $set.score = body.score; + if (body.time !== undefined) $set.time = body.time; + if (body.memory !== undefined) $set.memory = body.memory; + if (body.progress !== undefined) $set.progress = body.progress; rdoc = await record.update(body.domainId, body.rid, $set, $push); bus.boardcast('record/change', rdoc, $set, $push); } @@ -80,11 +80,11 @@ export async function end(body: JudgeResultBody) { $push.compilerTexts = body.compilerText; } if (body.status) $set.status = body.status; - if (body.score) $set.score = body.score; - if (body.time) $set.time = body.time; - if (body.memory) $set.memory = body.memory; + if (body.score !== undefined) $set.score = body.score; + if (body.time !== undefined) $set.time = body.time; + if (body.memory !== undefined) $set.memory = body.memory; $set.judgeAt = new Date(); - $set.judger = body.judger; + $set.judger = body.judger ?? 1; rdoc = await record.update(body.domainId, body.rid, $set, $push, $unset); await _postJudge(rdoc); bus.boardcast('record/change', rdoc); // trigger a full update diff --git a/packages/hydrooj/src/service/bus.ts b/packages/hydrooj/src/service/bus.ts index eb9c05d38..63a4d99a6 100644 --- a/packages/hydrooj/src/service/bus.ts +++ b/packages/hydrooj/src/service/bus.ts @@ -1,6 +1,7 @@ /* eslint-disable no-await-in-loop */ import cluster from 'cluster'; import { Db, FilterQuery } from 'mongodb'; +import { argv } from 'yargs'; import { Logger } from '../logger'; import { Mdoc, Pdoc, Rdoc, TrainingDoc, User, @@ -112,7 +113,7 @@ export function emit(name: K, ...args: Parameters(name: K, ...args: Parameters): Promise { - logger.debug('serial: %s %o', name, args); + if (argv.showBus) logger.debug('serial: %s %o', name, args); const hooks = Array.from(_hooks[name] || []); for (const callback of hooks) { await callback.apply(this, args); @@ -120,7 +121,7 @@ export async function serial(name: K, ...args: Paramet } export function bail(name: K, ...args: Parameters): ReturnType { - logger.debug('bail: %s %o', name, args); + if (argv.showBus) logger.debug('bail: %s %o', name, args); const hooks = Array.from(_hooks[name] || []); for (const callback of hooks) { const result = callback.apply(this, args);