Files
Hydro/packages/hydrojudge/src/judge/default.ts
T

89 lines
3.5 KiB
TypeScript

import { NormalizedCase, STATUS } from '@hydrooj/common';
import checkers from '../checkers';
import { runFlow } from '../flow';
import { del, runQueued } from '../sandbox';
import signals from '../signals';
import { Context, ContextSubTask } from './interface';
function judgeCase(c: NormalizedCase) {
return async (ctx: Context, ctxSubtask: ContextSubTask, runner?: Function) => {
const { address_space_limit, process_limit } = ctx.session.getLang(ctx.lang);
const res = await runQueued(
ctx.execute.execute,
{
stdin: { src: c.input },
copyIn: ctx.execute.copyIn,
filename: ctx.config.filename,
time: c.time,
memory: c.memory,
cacheStdoutAndStderr: true,
addressSpaceLimit: address_space_limit,
processLimit: process_limit,
},
`judgeCase[${c.id}]<${ctx.rid}>`,
);
const {
code, signalled, time, memory, fileIds,
} = res;
let { status } = res;
let message: any = '';
let score = 0;
const detail = ctx.config.detail ?? true;
if (status === STATUS.STATUS_ACCEPTED) {
if (time > c.time) {
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
} else if (memory > c.memory * 1024) {
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
} else {
({ status, score, message } = await checkers[ctx.config.checker_type]({
execute: ctx.checker.execute,
copyIn: ctx.checker.copyIn || {},
input: { src: c.input },
output: { src: c.output },
user_stdout: fileIds.stdout ? { fileId: fileIds.stdout } : { content: '' },
user_stderr: fileIds.stderr ? { fileId: fileIds.stderr } : { content: '' },
score: c.score,
detail,
env: {
...ctx.env,
HYDRO_TESTCASE: c.id.toString(),
HYDRO_TIME_USAGE: time.toString(),
HYDRO_MEMORY_USAGE: Math.floor(memory / 1024).toString(),
},
}));
}
} else if (status === STATUS.STATUS_RUNTIME_ERROR && code && detail) {
if (code < 32 && signalled) message = signals[code];
else message = { message: 'Your program returned {0}.', params: [code] };
}
await Promise.allSettled(Object.values(res.fileIds).map((id) => del(id)));
if (runner && ctx.rerun && c.time <= 5000 && status === STATUS.STATUS_TIME_LIMIT_EXCEEDED) {
ctx.rerun--;
return await runner(ctx, ctxSubtask);
}
if (!ctx.request.rejudged && !ctx.analysis && [STATUS.STATUS_WRONG_ANSWER, STATUS.STATUS_RUNTIME_ERROR].includes(status)) {
ctx.analysis = true;
await ctx.runAnalysis(ctx.execute, { src: c.input });
}
return {
id: c.id,
subtaskId: ctxSubtask.subtask.id,
status,
score,
time,
memory,
message,
};
};
}
export const judge = async (ctx: Context) => await runFlow(ctx, {
compile: async () => {
[ctx.execute, ctx.checker] = await Promise.all([
ctx.compile(ctx.lang, ctx.code),
ctx.compileLocalFile('checker', ctx.config.checker, ctx.config.checker_type),
]);
},
judgeCase,
});