mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
judge: provide score & subtaskId
This commit is contained in:
1 parent
60aa0e1611
commit
a585c13a72
19 files changed
+118
-186
No files matched your search
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hydrooj/hydrojudge",
|
||||
"bin": "bin/hydrojudge.js",
|
||||
"version": "2.19.4",
|
||||
"version": "2.20.0",
|
||||
"main": "package.json",
|
||||
"author": "undefined <i@undefined.moe>",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
|
||||
@@ -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] } },
|
||||
|
||||
@@ -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<JudgeResultBody>, 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<JudgeResultBody>) {
|
||||
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,
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
@@ -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<JudgeResultBody>, id?: number): void;
|
||||
end(data: Partial<JudgeResultBody>): void;
|
||||
getLang: (name: string) => LangConfig;
|
||||
|
||||
stat: Record<string, Date>;
|
||||
@@ -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<string, [string, string]>;
|
||||
|
||||
checker?: string;
|
||||
@@ -86,24 +68,8 @@ export interface Config {
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface SubTask {
|
||||
time: number;
|
||||
memory: number;
|
||||
type: 'sum' | 'max' | 'min';
|
||||
score: number;
|
||||
cases: Record<string, Case>;
|
||||
if: string[];
|
||||
}
|
||||
|
||||
export interface ContextSubTask {
|
||||
subtask: SubTask;
|
||||
subtask: NormalizedSubtask;
|
||||
score: number;
|
||||
status: number;
|
||||
}
|
||||
|
||||
export interface Case {
|
||||
id: number;
|
||||
input: string;
|
||||
output: string;
|
||||
score: number;
|
||||
}
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
@@ -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,
|
||||
});
|
||||
};
|
||||
@@ -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<JudgeResultBody>, 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<JudgeResultBody>) => {
|
||||
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<typeof getNext>;
|
||||
end: ReturnType<typeof getEnd>;
|
||||
tmpdir: string;
|
||||
clean: (() => Promise<any>)[];
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "3.13.4",
|
||||
"version": "3.13.5",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "src/loader",
|
||||
"module": "src/loader",
|
||||
|
||||
@@ -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<JudgeResultBody>) {
|
||||
body.rid = new ObjectID(body.rid);
|
||||
let rdoc = await record.get(body.rid);
|
||||
if (!rdoc) return;
|
||||
const $set: Partial<RecordDoc> = {};
|
||||
const $push: any = {};
|
||||
if (body.case) {
|
||||
const c: TestCase = {
|
||||
const c: Required<TestCase> = {
|
||||
...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<JudgeResultBody>) {
|
||||
if (body.rid) body.rid = new ObjectID(body.rid);
|
||||
let rdoc = await record.get(body.rid);
|
||||
if (!rdoc) return;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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<string, ContentNode[]>;
|
||||
|
||||
@@ -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<TestCase>[];
|
||||
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<any>?, 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'),
|
||||
|
||||
@@ -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},`;
|
||||
|
||||
@@ -200,9 +200,13 @@ const tasks = {
|
||||
},
|
||||
record: async (doc) => {
|
||||
if (doc.hidden) return null;
|
||||
const testCases: TestCase[] = [];
|
||||
const testCases: Required<TestCase>[] = [];
|
||||
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,
|
||||
|
||||
@@ -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<ParsedCase>;
|
||||
interface NormalizedSubtask extends Required<ParsedSubtask> {
|
||||
export interface NormalizedCase extends Required<ParsedCase> {
|
||||
time: number;
|
||||
memory: number;
|
||||
}
|
||||
export interface NormalizedSubtask extends Required<ParsedSubtask> {
|
||||
cases: NormalizedCase[];
|
||||
time: number;
|
||||
memory: number;
|
||||
}
|
||||
|
||||
export function normalizeSubtasks(
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user