diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index 6f261fb4b..f129c1976 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -1,7 +1,7 @@ { "name": "@hydrooj/hydrojudge", "bin": "bin/hydrojudge.js", - "version": "2.19.4", + "version": "2.20.0", "main": "package.json", "author": "undefined ", "repository": "https://github.com/hydro-dev/Hydro.git", diff --git a/packages/hydrojudge/src/compile.ts b/packages/hydrojudge/src/compile.ts index eb767152b..76c170c5c 100644 --- a/packages/hydrojudge/src/compile.ts +++ b/packages/hydrojudge/src/compile.ts @@ -25,7 +25,7 @@ export = async function compile( ); if (status !== STATUS.STATUS_ACCEPTED) throw new CompileError({ status, stdout, stderr }); if (!fileIds[target]) throw new CompileError({ stderr: 'Executable file not found.' }); - if (next) next({ compiler_text: compilerText(stdout, stderr) }); + if (next) next({ compilerText: compilerText(stdout, stderr) }); return { execute, copyIn: { ...copyIn, [target]: { fileId: fileIds[target] } }, diff --git a/packages/hydrojudge/src/hosts/hydro.ts b/packages/hydrojudge/src/hosts/hydro.ts index 950975099..072e000c1 100644 --- a/packages/hydrojudge/src/hosts/hydro.ts +++ b/packages/hydrojudge/src/hosts/hydro.ts @@ -9,12 +9,13 @@ import PQueue from 'p-queue'; import WebSocket from 'ws'; import { LangConfig } from '@hydrooj/utils/lib/lang'; import { STATUS } from '@hydrooj/utils/lib/status'; +import type { JudgeResultBody } from 'hydrooj'; import readCases from '../cases'; import { getConfig } from '../config'; import { CompileError, FormatError, SystemError } from '../error'; import judge from '../judge'; import log from '../log'; -import { CopyInFile } from '../sandbox/interface'; +import type { CopyInFile } from '../sandbox/interface'; import * as sysinfo from '../sysinfo'; import * as tmpfs from '../tmpfs'; import { @@ -82,21 +83,21 @@ class JudgeTask { await this.doSubmission(startPromise); } catch (e) { if (e instanceof CompileError) { - this.next({ compiler_text: compilerText(e.stdout, e.stderr) }); + this.next({ compilerText: compilerText(e.stdout, e.stderr) }); this.end({ - status: STATUS.STATUS_COMPILE_ERROR, score: 0, time_ms: 0, memory_kb: 0, + status: STATUS.STATUS_COMPILE_ERROR, score: 0, time: 0, memory: 0, }); } else if (e instanceof FormatError) { - this.next({ judge_text: 'Testdata configuration incorrect.' }); - this.next({ judge_text: { message: e.message, params: e.params } }); + this.next({ message: 'Testdata configuration incorrect.' }); + this.next({ message: { message: e.message, params: e.params } }); this.end({ - status: STATUS.STATUS_FORMAT_ERROR, score: 0, time_ms: 0, memory_kb: 0, + status: STATUS.STATUS_FORMAT_ERROR, score: 0, time: 0, memory: 0, }); } else { log.error(e); this.next({ message: { message: e.message, params: e.params || [], ...argv.options.debug ? { stack: e.stack } : {} } }); this.end({ - status: STATUS.STATUS_SYSTEM_ERROR, score: 0, time_ms: 0, memory_kb: 0, + status: STATUS.STATUS_SYSTEM_ERROR, score: 0, time: 0, memory: 0, }); } } finally { @@ -132,38 +133,21 @@ class JudgeTask { await judge[type].judge(this, startPromise); } - next(data, id?: number) { + next(data: Partial, id?: number) { log.debug('Next: %d %o', id, data); data.key = 'next'; data.rid = new ObjectID(this.rid); - if (data.time_ms) data.time = data.time_ms; - if (data.memory_kb) data.memory = data.memory_kb; - if (data.compiler_text) data.compilerText = data.compiler_text; - if (data.judge_text) data.message = data.judge_text; - delete data.time_ms; - delete data.memory_kb; - delete data.compiler_text; - delete data.judge_text; if (data.case) { - data.case = { - id, - status: data.case.status, - time: data.case.time_ms || data.case.time, - memory: data.case.memory_kb || data.case.memory, - message: data.case.message || data.case.judgeText || data.case.judge_text || '', - }; + data.case.id ||= id; + data.case.message ||= ''; } this.ws.send(JSON.stringify(data)); } - end(data) { + end(data: Partial) { log.info('End: %o', data); data.key = 'end'; - data.rid = new ObjectID(this.request.rid); - data.time = data.time_ms ?? data.time; - delete data.time_ms; - data.memory = data.memory_kb ?? data.memory; - delete data.memory_kb; + data.rid = this.request.rid; this.ws.send(JSON.stringify(data)); } } @@ -221,7 +205,7 @@ export default class Hydro { } if (filenames.length) { log.info(`Getting problem data: ${this.config.host}/${source}`); - if (next) next({ judge_text: 'Syncing testdata, please wait...' }); + if (next) next({ message: 'Syncing testdata, please wait...' }); await this.ensureLogin(); const res = await this.axios.post(`/d/${domainId}/judge/files`, { pid: +pid, diff --git a/packages/hydrojudge/src/judge/default.ts b/packages/hydrojudge/src/judge/default.ts index 976cb5867..a1efc69e4 100644 --- a/packages/hydrojudge/src/judge/default.ts +++ b/packages/hydrojudge/src/judge/default.ts @@ -8,10 +8,8 @@ import { Logger } from '../log'; import { del, run } from '../sandbox'; import { CmdFile } from '../sandbox/interface'; import signals from '../signals'; -import { parseFilename } from '../utils'; -import { - Case, Context, ContextSubTask, SubTask, -} from './interface'; +import { NormalizedCase, NormalizedSubtask, parseFilename } from '../utils'; +import { Context, ContextSubTask } from './interface'; const Score = { sum: (a: number, b: number) => (a + b), @@ -21,18 +19,18 @@ const Score = { const logger = new Logger('judge/default'); -function judgeCase(c: Case, sid: string) { +function judgeCase(c: NormalizedCase, sid: string) { return async (ctx: Context, ctxSubtask: ContextSubTask, runner?: Function) => { if (ctx.errored || (ctx.failed[sid] && ctxSubtask.subtask.type === 'min') || (ctxSubtask.subtask.type === 'max' && ctxSubtask.score === ctxSubtask.subtask.score) - || ((ctxSubtask.subtask.if || []).filter((i: string) => ctx.failed[i]).length) + || ((ctxSubtask.subtask.if || []).filter((i) => ctx.failed[i]).length) ) { ctx.next({ case: { status: STATUS.STATUS_CANCELED, score: 0, - time_ms: 0, - memory_kb: 0, + time: 0, + memory: 0, message: '', }, addProgress: 100 / ctx.config.count, @@ -100,10 +98,11 @@ function judgeCase(c: Case, sid: string) { ctx.total_memory_usage_kb = Math.max(ctx.total_memory_usage_kb, memory_usage_kb); ctx.next({ case: { + subtaskId: ctxSubtask.subtask.id, status, - score: 0, - time_ms: time_usage_ms, - memory_kb: memory_usage_kb, + score, + time: time_usage_ms, + memory: memory_usage_kb, message, }, addProgress: 100 / ctx.config.count, @@ -126,7 +125,7 @@ function judgeCase(c: Case, sid: string) { env: ctx.env, }); const out = r.stdout.toString(); - if (out.length) ctx.next({ compiler_text: out.substring(0, 1024) }); + if (out.length) ctx.next({ compilerText: out.substring(0, 1024) }); if (process.env.DEV) console.log(r); } catch (e) { logger.info('Failed to run analysis'); @@ -137,7 +136,7 @@ function judgeCase(c: Case, sid: string) { }; } -function judgeSubtask(subtask: SubTask, sid: string) { +function judgeSubtask(subtask: NormalizedSubtask, sid: string) { return async (ctx: Context) => { subtask.type = subtask.type || 'min'; const ctxSubtask = { @@ -219,7 +218,7 @@ export const judge = async (ctx: Context, startPromise = Promise.resolve()) => { ctx.end({ status: ctx.total_status, score: ctx.total_score, - time_ms: Math.floor(ctx.total_time_usage_ms * 1000000) / 1000000, - memory_kb: ctx.total_memory_usage_kb, + time: Math.floor(ctx.total_time_usage_ms * 1000000) / 1000000, + memory: ctx.total_memory_usage_kb, }); }; diff --git a/packages/hydrojudge/src/judge/interactive.ts b/packages/hydrojudge/src/judge/interactive.ts index cc7d492a4..2e556ad07 100644 --- a/packages/hydrojudge/src/judge/interactive.ts +++ b/packages/hydrojudge/src/judge/interactive.ts @@ -5,10 +5,10 @@ import { getConfig } from '../config'; import { runPiped } from '../sandbox'; import signals from '../signals'; import { parse } from '../testlib'; -import { findFileSync, parseFilename } from '../utils'; import { - Case, Context, ContextSubTask, SubTask, -} from './interface'; + findFileSync, NormalizedCase, NormalizedSubtask, parseFilename, +} from '../utils'; +import { Context, ContextSubTask } from './interface'; const testlibSrc = findFileSync('@hydrooj/hydrojudge/vendor/testlib/testlib.h'); const Score = { @@ -17,7 +17,7 @@ const Score = { min: Math.min, }; -function judgeCase(c: Case) { +function judgeCase(c: NormalizedCase) { return async (ctx: Context, ctxSubtask: ContextSubTask) => { ctx.executeInteractor.copyIn.in = c.input ? { src: c.input } : { content: '' }; ctx.executeInteractor.copyIn.out = c.output ? { src: c.output } : { content: '' }; @@ -63,10 +63,11 @@ function judgeCase(c: Case) { ctx.next({ status: STATUS.STATUS_JUDGING, case: { + subtaskId: ctxSubtask.subtask.id, status, score, - time_ms: time_usage_ms, - memory_kb: memory_usage_kb, + time: time_usage_ms, + memory: memory_usage_kb, message, }, progress: Math.floor((c.id * 100) / ctx.config.count), @@ -74,7 +75,7 @@ function judgeCase(c: Case) { }; } -function judgeSubtask(subtask: SubTask) { +function judgeSubtask(subtask: NormalizedSubtask) { return async (ctx: Context) => { subtask.type = subtask.type || 'min'; const ctxSubtask = { @@ -134,7 +135,7 @@ export const judge = async (ctx: Context, startPromise = Promise.resolve()) => { ctx.end({ status: ctx.total_status, score: ctx.total_score, - time_ms: ctx.total_time_usage_ms, - memory_kb: ctx.total_memory_usage_kb, + time: ctx.total_time_usage_ms, + memory: ctx.total_memory_usage_kb, }); }; diff --git a/packages/hydrojudge/src/judge/interface.ts b/packages/hydrojudge/src/judge/interface.ts index 448ae7cef..bfad1f22d 100644 --- a/packages/hydrojudge/src/judge/interface.ts +++ b/packages/hydrojudge/src/judge/interface.ts @@ -1,31 +1,15 @@ import PQueue from 'p-queue'; -import { LangConfig } from '@hydrooj/utils/lib/lang'; +import type { NormalizedSubtask } from '@hydrooj/utils/lib/common'; +import type { LangConfig } from '@hydrooj/utils/lib/lang'; +import type { JudgeResultBody } from 'hydrooj'; import { Execute } from '../interface'; import { CopyInFile } from '../sandbox/interface'; export type Context = JudgeTaskInterface & RuntimeContext; export interface JudgeTaskInterface { - next(arg0: { - compiler_text?: string; - status?: number; - message?: string; - progress?: number; - addProgress?: number; - case?: { - status: number; - score?: number; - time_ms: number; - memory_kb: number; - message: string; - }; - }, arg1?: number): void; - end(arg0: { - status: number; - score: number; - time_ms: number; - memory_kb: number; - }): void; + next(data: Partial, id?: number): void; + end(data: Partial): void; getLang: (name: string) => LangConfig; stat: Record; @@ -56,22 +40,20 @@ export interface RuntimeContext { executeUser?: Execute; } -type ExtraFile = string[]; - export interface Config { type: string; subType?: string; time: string; memory: string; - subtasks?: SubTask[]; + subtasks?: NormalizedSubtask[]; count?: number; checker_type?: string; detail?: boolean; filename?: string; - judge_extra_files?: ExtraFile; - user_extra_files?: ExtraFile; + judge_extra_files?: string[]; + user_extra_files?: string[]; template?: Record; checker?: string; @@ -86,24 +68,8 @@ export interface Config { }[]; } -export interface SubTask { - time: number; - memory: number; - type: 'sum' | 'max' | 'min'; - score: number; - cases: Record; - if: string[]; -} - export interface ContextSubTask { - subtask: SubTask; + subtask: NormalizedSubtask; score: number; status: number; } - -export interface Case { - id: number; - input: string; - output: string; - score: number; -} diff --git a/packages/hydrojudge/src/judge/objective.ts b/packages/hydrojudge/src/judge/objective.ts index 278c1b538..0d6a374fb 100644 --- a/packages/hydrojudge/src/judge/objective.ts +++ b/packages/hydrojudge/src/judge/objective.ts @@ -29,11 +29,11 @@ export async function judge({ status: totalStatus, progress: (100 * (+i + 1)) / config.outputs.length, case: { - status, score, time_ms: 0, memory_kb: 0, message: '', + status, score, time: 0, memory: 0, message: '', }, }, +i + 1); } return end({ - status: totalStatus, score: totalScore, time_ms: 0, memory_kb: 0, + status: totalStatus, score: totalScore, time: 0, memory: 0, }); } diff --git a/packages/hydrojudge/src/judge/run.ts b/packages/hydrojudge/src/judge/run.ts index c746ea2d8..c87503ec8 100644 --- a/packages/hydrojudge/src/judge/run.ts +++ b/packages/hydrojudge/src/judge/run.ts @@ -12,8 +12,8 @@ import { Context } from './interface'; const failure = (status: number, message?: string) => ({ status, score: 0, - time_ms: 0, - memory_kb: 0, + time: 0, + memory: 0, message, }); @@ -88,9 +88,11 @@ export const judge = async (ctx: Context) => { ctx.next({ status, case: { + subtaskId: 0, status, - time_ms: time_usage_ms, - memory_kb: memory_usage_kb, + score: 100, + time: time_usage_ms, + memory: memory_usage_kb, message: message.join('\n').substring(0, 102400), }, }); @@ -115,7 +117,7 @@ export const judge = async (ctx: Context) => { memory: 256, }); const out = r.stdout.toString(); - if (out.length) ctx.next({ compiler_text: out.substring(0, 1024) }); + if (out.length) ctx.next({ compilerText: out.substring(0, 1024) }); if (process.env.DEV) console.log(r); } catch (e) { logger.info('Failed to run analysis'); @@ -128,7 +130,7 @@ export const judge = async (ctx: Context) => { ctx.end({ status, score: status === STATUS.STATUS_ACCEPTED ? 100 : 0, - time_ms: Math.floor(time_usage_ms * 1000000) / 1000000, - memory_kb: memory_usage_kb, + time: Math.floor(time_usage_ms * 1000000) / 1000000, + memory: memory_usage_kb, }); }; diff --git a/packages/hydrojudge/src/judge/submit_answer.ts b/packages/hydrojudge/src/judge/submit_answer.ts index d0623a795..00c3fa9d8 100644 --- a/packages/hydrojudge/src/judge/submit_answer.ts +++ b/packages/hydrojudge/src/judge/submit_answer.ts @@ -5,10 +5,8 @@ import { check, compileChecker } from '../check'; import { getConfig } from '../config'; import { FormatError } from '../error'; import { del, run } from '../sandbox'; -import { parseFilename } from '../utils'; -import { - Case, Context, ContextSubTask, SubTask, -} from './interface'; +import { NormalizedCase, NormalizedSubtask, parseFilename } from '../utils'; +import { Context, ContextSubTask } from './interface'; const Score = { sum: (a: number, b: number) => (a + b), @@ -16,18 +14,18 @@ const Score = { min: Math.min, }; -function judgeCase(c: Case, sid: string) { +function judgeCase(c: NormalizedCase, sid: string) { return async (ctx: Context, ctxSubtask: ContextSubTask) => { if (ctx.errored || (ctx.failed[sid] && ctxSubtask.subtask.type === 'min') || (ctxSubtask.subtask.type === 'max' && ctxSubtask.score === ctxSubtask.subtask.score) - || ((ctxSubtask.subtask.if || []).filter((i: string) => ctx.failed[i]).length) + || ((ctxSubtask.subtask.if || []).filter((i) => ctx.failed[i]).length) ) { ctx.next({ case: { status: STATUS.STATUS_CANCELED, score: 0, - time_ms: 0, - memory_kb: 0, + time: 0, + memory: 0, message: '', }, addProgress: 100 / ctx.config.count, @@ -87,8 +85,8 @@ function judgeCase(c: Case, sid: string) { case: { status, score: 0, - time_ms: 0, - memory_kb: 0, + time: 0, + memory: 0, message, }, addProgress: 100 / ctx.config.count, @@ -96,7 +94,7 @@ function judgeCase(c: Case, sid: string) { }; } -function judgeSubtask(subtask: SubTask, sid: string) { +function judgeSubtask(subtask: NormalizedSubtask, sid: string) { return async (ctx: Context) => { subtask.type = subtask.type || 'min'; const ctxSubtask = { @@ -160,7 +158,7 @@ export const judge = async (ctx: Context, startPromise = Promise.resolve()) => { ctx.end({ status: ctx.total_status, score: ctx.total_score, - time_ms: 0, - memory_kb: 0, + time: 0, + memory: 0, }); }; diff --git a/packages/hydrojudge/src/service.ts b/packages/hydrojudge/src/service.ts index cace7bd8f..bec7390e5 100644 --- a/packages/hydrojudge/src/service.ts +++ b/packages/hydrojudge/src/service.ts @@ -7,6 +7,7 @@ import fs from 'fs-extra'; import { noop } from 'lodash'; import { ObjectID } from 'mongodb'; import { STATUS } from '@hydrooj/utils/lib/status'; +import type { JudgeResultBody } from 'hydrooj'; import { Logger } from 'hydrooj/src/logger'; import * as monitor from 'hydrooj/src/service/monitor'; import readCases from './cases'; @@ -108,34 +109,18 @@ async function postInit() { } function getNext(that) { - return (data, id = 0) => { + return (data: Partial, id = 0) => { logger.debug('Next: %d %o', id, data); data.rid = new ObjectID(that.rid); - if (data.time_ms) data.time = data.time_ms; - if (data.memory_kb) data.memory = data.memory_kb; - if (data.compiler_text) data.compilerText = data.compiler_text; - delete data.time_ms; - delete data.memory_kb; - delete data.compiler_text; - if (data.case) { - data.case = { - id, - status: data.case.status, - time: data.case.time_ms || data.case.time, - memory: data.case.memory_kb || data.case.memory, - message: data.case.message || data.case.judgeText || '', - }; - } + if (data.case) data.case.id ||= id; _judge.next(data); }; } function getEnd(rid: string) { - return (data) => { + return (data: Partial) => { data.key = 'end'; data.rid = new ObjectID(rid); - 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); }; @@ -160,8 +145,8 @@ async function postInit() { config: any; env: any; input?: string; - next: (data: any, id?: number) => void; - end: (data: any) => void; + next: ReturnType; + end: ReturnType; tmpdir: string; clean: (() => Promise)[]; folder: string; @@ -204,20 +189,20 @@ async function postInit() { await this.submission(); } catch (e) { if (e instanceof CompileError) { - this.next({ compiler_text: compilerText(e.stdout, e.stderr) }); + this.next({ compilerText: compilerText(e.stdout, e.stderr) }); this.end({ - status: STATUS.STATUS_COMPILE_ERROR, score: 0, time_ms: 0, memory_kb: 0, + status: STATUS.STATUS_COMPILE_ERROR, score: 0, time: 0, memory: 0, }); } else if (e instanceof FormatError) { this.next({ message: { message: e.message, params: e.params } }); this.end({ - status: STATUS.STATUS_FORMAT_ERROR, score: 0, time_ms: 0, memory_kb: 0, + status: STATUS.STATUS_FORMAT_ERROR, score: 0, time: 0, memory: 0, }); } else { logger.error(e); this.next({ message: { message: e.message, params: e.params, ...process.env.DEV ? { stack: e.stack } : {} } }); this.end({ - status: STATUS.STATUS_SYSTEM_ERROR, score: 0, time_ms: 0, memory_kb: 0, + status: STATUS.STATUS_SYSTEM_ERROR, score: 0, time: 0, memory: 0, }); } } diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index ce577180e..01e9eb2e4 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "3.13.4", + "version": "3.13.5", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", diff --git a/packages/hydrooj/src/handler/judge.ts b/packages/hydrooj/src/handler/judge.ts index e1fb46ee9..283289c52 100644 --- a/packages/hydrooj/src/handler/judge.ts +++ b/packages/hydrooj/src/handler/judge.ts @@ -41,19 +41,19 @@ export async function postJudge(rdoc: RecordDoc) { await bus.serial('record/judge', rdoc, updated); } -export async function next(body: JudgeResultBody) { +export async function next(body: Partial) { body.rid = new ObjectID(body.rid); let rdoc = await record.get(body.rid); if (!rdoc) return; const $set: Partial = {}; const $push: any = {}; if (body.case) { - const c: TestCase = { + const c: Required = { + ...body.case, id: body.case.id || 0, - memory: body.case.memory, - time: body.case.time, + subtaskId: body.case.subtaskId || 0, + score: body.case.score || 0, message: body.case.message || '', - status: body.case.status, }; rdoc.testCases.push(c); $push.testCases = c; @@ -75,7 +75,7 @@ export async function next(body: JudgeResultBody) { bus.broadcast('record/change', rdoc!, $set, $push); } -export async function end(body: JudgeResultBody) { +export async function end(body: Partial) { if (body.rid) body.rid = new ObjectID(body.rid); let rdoc = await record.get(body.rid); if (!rdoc) return; diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index 5dffb71b2..00760623b 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -289,7 +289,6 @@ export class ProblemRandomHandler extends ProblemHandler { const category = flattenDeep(decodeURIComponent(qs).split(' ') .filter((i) => i.startsWith('category:')) .map((i) => i.split('category:')[1]?.split(','))); - console.log(qs, category); const q = buildQuery(this.user); if (category.length) q.$and = category.map((tag) => ({ tag })); await bus.serial('problem/list', q, this); diff --git a/packages/hydrooj/src/handler/record.ts b/packages/hydrooj/src/handler/record.ts index 6a90f5411..b21152259 100644 --- a/packages/hydrooj/src/handler/record.ts +++ b/packages/hydrooj/src/handler/record.ts @@ -183,7 +183,7 @@ class RecordDetailHandler extends Handler { time: 0, memory: 0, testCases: [{ - status: 9, score: 0, time: 0, memory: 0, message: 'score canceled', + id: 0, subtaskId: 0, status: 9, score: 0, time: 0, memory: 0, message: 'score canceled', }], }; const [latest] = await Promise.all([ diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index dc33df041..34a7d902a 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -2,7 +2,6 @@ import type fs from 'fs'; import type { Dictionary, NumericDictionary } from 'lodash'; import type { ItemBucketMetadata } from 'minio'; import type { Cursor, ObjectID } from 'mongodb'; -import type { Readable, Writable } from 'stream'; import type { ProblemDoc } from './model/problem'; type document = typeof import('./model/document'); @@ -208,6 +207,7 @@ export interface SampleContentNode { sectionTitle: string, payload: [string, string], } +// TODO drop contentNode support export type ContentNode = PlainContentNode | TextContentNode | SampleContentNode; export type Content = string | ContentNode[] | Record; @@ -272,6 +272,8 @@ export interface ProblemStatusDoc extends StatusDoc { export interface TestCase { id?: number; + subtaskId?: number; + score?: number; time: number; memory: number; status: number; @@ -288,9 +290,9 @@ export interface RecordDoc { score: number; memory: number; time: number; - judgeTexts: string[]; + judgeTexts: (string | JudgeMessage)[]; compilerTexts: string[]; - testCases: TestCase[]; + testCases: Required[]; rejudged: boolean; source?: string; /** judge uid */ @@ -497,24 +499,25 @@ export interface Script { validate: any, } +export interface JudgeMessage { + message: string; + params?: string[]; + stack?: string; +} + export interface JudgeResultBody { + key: string; domainId: string; rid: ObjectID; judger?: number; progress?: number; addProgress?: number; - case?: { - id?: number; - status: number; - time: number; - memory: number; - message?: string; - }, + case?: TestCase, status?: number; score?: number; time?: number; memory?: number; - message?: string; + message?: string | JudgeMessage; compilerText?: string, } @@ -527,19 +530,6 @@ export interface Task { [key: string]: any; } -export interface UploadStream extends Writable { - id: ObjectID; -} - -export interface HydroFileSystem { - openUploadStream: (filename: string) => UploadStream - openDownloadStream: (_id: ObjectID) => Readable - // TODO - find: (...args: any[]) => any -} - -export type PathComponent = [string, string, Dictionary?, boolean?]; - export interface BaseService { started: boolean; error?: Error | string; @@ -637,7 +627,6 @@ export interface Model { export interface Service { bus: typeof import('./service/bus'), db: typeof import('./service/db'), - fs: HydroFileSystem, monitor: typeof import('./service/monitor'), server: typeof import('./service/server'), storage: typeof import('./service/storage'), diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index 13719f8cf..417ed376c 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -95,7 +95,7 @@ app.on('error', (error) => { } }); wsServer.on('error', (error) => { - console.log(123, error); + console.log('Websocket server error:', error); }); const ignoredLimit = `,${argv.options.ignoredLimit},`; diff --git a/packages/migrate/scripts/vijos.ts b/packages/migrate/scripts/vijos.ts index 0aa6ffea7..4af1515a6 100644 --- a/packages/migrate/scripts/vijos.ts +++ b/packages/migrate/scripts/vijos.ts @@ -200,9 +200,13 @@ const tasks = { }, record: async (doc) => { if (doc.hidden) return null; - const testCases: TestCase[] = []; + const testCases: Required[] = []; + let i = 1; for (const c of doc.cases || []) { testCases.push({ + id: i++, + subtaskId: 0, + score: 0, status: c.status, time: c.time_ms || c.time, memory: c.memory_kb || c.memory, diff --git a/packages/utils/lib/common.ts b/packages/utils/lib/common.ts index 9b0b834af..1d1d24240 100644 --- a/packages/utils/lib/common.ts +++ b/packages/utils/lib/common.ts @@ -173,7 +173,7 @@ interface MatchRule { const SubtaskMatcher: MatchRule[] = [ { - regex: /^([^\d]*)(\d+).(in|txt)$/, + regex: /^([^\d]*(?:\d+[a-zA-Z]+)*)(\d+).(in|txt)$/, output: [ (a) => `${a[1] + a[2]}.out`, (a) => `${a[1] + a[2]}.ans`, @@ -260,9 +260,14 @@ export function readSubtasksFromFiles(files: string[], config) { return Object.values(subtask); } -type NormalizedCase = Required; -interface NormalizedSubtask extends Required { +export interface NormalizedCase extends Required { + time: number; + memory: number; +} +export interface NormalizedSubtask extends Required { cases: NormalizedCase[]; + time: number; + memory: number; } export function normalizeSubtasks( diff --git a/packages/utils/package.json b/packages/utils/package.json index be1e54208..d12a23eba 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/utils", - "version": "1.2.3", + "version": "1.2.4", "description": "hydrooj utils", "main": "package.json", "repository": "https://github.com/hydro-dev/Hydro.git",