refactor(config/judge.ts, types/judge.ts): split judge configuration and types

This commit is contained in:
cfngc4594 2025-03-05 09:27:00 +08:00
parent 808dd96a50
commit a33033b48d
3 changed files with 65 additions and 53 deletions

View File

@ -3,7 +3,9 @@
import tar from "tar-stream";
import Docker from "dockerode";
import { Readable, Writable } from "stream";
import { ExitCode, JudgeResult, LanguageConfigs } from "@/config/judge";
import { JudgeConfig } from "@/config/judge";
import { EditorLanguage } from "@/types/editor-language";
import { ExitCode, JudgeResultMetadata } from "@/types/judge";
// Docker client initialization
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
@ -41,10 +43,11 @@ function createTarStream(file: string, value: string) {
}
export async function judge(
language: string,
language: EditorLanguage,
value: string
): Promise<JudgeResult> {
const { fileName, fileExtension, image, tag, workingDir, memoryLimit, timeLimit, compileOutputLimit, runOutputLimit } = LanguageConfigs[language];
): Promise<JudgeResultMetadata> {
const { fileName, fileExtension } = JudgeConfig[language].editorLanguageMetadata;
const { image, tag, workingDir, memoryLimit, timeLimit, compileOutputLimit, runOutputLimit } = JudgeConfig[language].dockerMetadata;
const file = `${fileName}.${fileExtension}`;
let container: Docker.Container | undefined;
@ -70,14 +73,14 @@ export async function judge(
}
}
async function compile(container: Docker.Container, file: string, fileName: string, maxOutput: number = 1 * 1024 * 1024): Promise<JudgeResult> {
async function compile(container: Docker.Container, file: string, fileName: string, maxOutput: number = 1 * 1024 * 1024): Promise<JudgeResultMetadata> {
const compileExec = await container.exec({
Cmd: ["gcc", "-O2", file, "-o", fileName],
AttachStdout: true,
AttachStderr: true,
});
return new Promise<JudgeResult>((resolve, reject) => {
return new Promise<JudgeResultMetadata>((resolve, reject) => {
compileExec.start({}, (error, stream) => {
if (error || !stream) {
return reject({ output: "System Error", exitCode: ExitCode.SE });
@ -126,7 +129,7 @@ async function compile(container: Docker.Container, file: string, fileName: stri
const stderr = stderrChunks.join("");
const exitCode = (await compileExec.inspect()).ExitCode;
let result: JudgeResult;
let result: JudgeResultMetadata;
if (exitCode !== 0 || stderr) {
result = { output: stderr || "Compilation Error", exitCode: ExitCode.CE };
@ -145,14 +148,14 @@ async function compile(container: Docker.Container, file: string, fileName: stri
}
// Run code and implement timeout
async function run(container: Docker.Container, fileName: string, timeLimit?: number, maxOutput: number = 1 * 1024 * 1024): Promise<JudgeResult> {
async function run(container: Docker.Container, fileName: string, timeLimit?: number, maxOutput: number = 1 * 1024 * 1024): Promise<JudgeResultMetadata> {
const runExec = await container.exec({
Cmd: [`./${fileName}`],
AttachStdout: true,
AttachStderr: true,
});
return new Promise<JudgeResult>((resolve, reject) => {
return new Promise<JudgeResultMetadata>((resolve, reject) => {
const stdoutChunks: string[] = [];
let stdoutLength = 0;
const stdoutStream = new Writable({
@ -211,7 +214,7 @@ async function run(container: Docker.Container, fileName: string, timeLimit?: nu
const stderr = stderrChunks.join("");
const exitCode = (await runExec.inspect()).ExitCode;
let result: JudgeResult;
let result: JudgeResultMetadata;
// Exit code 0 means successful execution
if (exitCode === 0) {

View File

@ -1,42 +1,9 @@
// Result type definitions
export enum ExitCode {
SE = 0, // System Error
CS = 1, // Compilation Success
CE = 2, // Compilation Error
TLE = 3, // Time Limit Exceeded
MLE = 4, // Memory Limit Exceeded
RE = 5, // Runtime Error
AC = 6, // Accepted
WA = 7, // Wrong Answer
}
import { EditorLanguage } from "@/types/editor-language";
import { EditorLanguageConfig } from "./editor-language";
import { DockerMetadata, JudgeMetadata } from "@/types/judge";
export type JudgeResult = {
output: string;
exitCode: ExitCode;
executionTime?: number;
memoryUsage?: number;
};
export interface LanguageConfig {
id: string;
label: string;
fileName: string;
fileExtension: string;
image: string;
tag: string;
workingDir: string;
timeLimit: number;
memoryLimit: number;
compileOutputLimit: number;
runOutputLimit: number;
}
export const LanguageConfigs: Record<string, LanguageConfig> = {
c: {
id: "c",
label: "C",
fileName: "main",
fileExtension: "c",
export const DockerConfig: Record<EditorLanguage, DockerMetadata> = {
[EditorLanguage.C]: {
image: "gcc",
tag: "latest",
workingDir: "/src",
@ -45,11 +12,7 @@ export const LanguageConfigs: Record<string, LanguageConfig> = {
compileOutputLimit: 1 * 1024 * 1024,
runOutputLimit: 1 * 1024 * 1024,
},
cpp: {
id: "cpp",
label: "C++",
fileName: "main",
fileExtension: "cpp",
[EditorLanguage.CPP]: {
image: "gcc",
tag: "latest",
workingDir: "/src",
@ -57,5 +20,16 @@ export const LanguageConfigs: Record<string, LanguageConfig> = {
memoryLimit: 128,
compileOutputLimit: 1 * 1024 * 1024,
runOutputLimit: 1 * 1024 * 1024,
}
}
export const JudgeConfig: Record<EditorLanguage, JudgeMetadata> = {
[EditorLanguage.C]: {
editorLanguageMetadata: EditorLanguageConfig[EditorLanguage.C],
dockerMetadata: DockerConfig[EditorLanguage.C],
},
[EditorLanguage.CPP]: {
editorLanguageMetadata: EditorLanguageConfig[EditorLanguage.CPP],
dockerMetadata: DockerConfig[EditorLanguage.CPP],
},
};

35
src/types/judge.ts Normal file
View File

@ -0,0 +1,35 @@
import { EditorLanguageMetadata } from "./editor-language";
// Result type definitions
export enum ExitCode {
SE = 0, // System Error
CS = 1, // Compilation Success
CE = 2, // Compilation Error
TLE = 3, // Time Limit Exceeded
MLE = 4, // Memory Limit Exceeded
RE = 5, // Runtime Error
AC = 6, // Accepted
WA = 7, // Wrong Answer
}
export type JudgeResultMetadata = {
output: string;
exitCode: ExitCode;
executionTime?: number;
memoryUsage?: number;
};
export type JudgeMetadata = {
editorLanguageMetadata: EditorLanguageMetadata;
dockerMetadata: DockerMetadata;
};
export type DockerMetadata = {
image: string;
tag: string;
workingDir: string;
timeLimit: number;
memoryLimit: number;
compileOutputLimit: number;
runOutputLimit: number;
}