mirror of
https://github.com/massbug/judge4c.git
synced 2025-05-18 07:16:34 +00:00
refactor(config/judge.ts, types/judge.ts): split judge configuration and types
This commit is contained in:
parent
808dd96a50
commit
a33033b48d
@ -3,7 +3,9 @@
|
|||||||
import tar from "tar-stream";
|
import tar from "tar-stream";
|
||||||
import Docker from "dockerode";
|
import Docker from "dockerode";
|
||||||
import { Readable, Writable } from "stream";
|
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
|
// Docker client initialization
|
||||||
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
|
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
|
||||||
@ -41,10 +43,11 @@ function createTarStream(file: string, value: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function judge(
|
export async function judge(
|
||||||
language: string,
|
language: EditorLanguage,
|
||||||
value: string
|
value: string
|
||||||
): Promise<JudgeResult> {
|
): Promise<JudgeResultMetadata> {
|
||||||
const { fileName, fileExtension, image, tag, workingDir, memoryLimit, timeLimit, compileOutputLimit, runOutputLimit } = LanguageConfigs[language];
|
const { fileName, fileExtension } = JudgeConfig[language].editorLanguageMetadata;
|
||||||
|
const { image, tag, workingDir, memoryLimit, timeLimit, compileOutputLimit, runOutputLimit } = JudgeConfig[language].dockerMetadata;
|
||||||
const file = `${fileName}.${fileExtension}`;
|
const file = `${fileName}.${fileExtension}`;
|
||||||
let container: Docker.Container | undefined;
|
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({
|
const compileExec = await container.exec({
|
||||||
Cmd: ["gcc", "-O2", file, "-o", fileName],
|
Cmd: ["gcc", "-O2", file, "-o", fileName],
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Promise<JudgeResult>((resolve, reject) => {
|
return new Promise<JudgeResultMetadata>((resolve, reject) => {
|
||||||
compileExec.start({}, (error, stream) => {
|
compileExec.start({}, (error, stream) => {
|
||||||
if (error || !stream) {
|
if (error || !stream) {
|
||||||
return reject({ output: "System Error", exitCode: ExitCode.SE });
|
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 stderr = stderrChunks.join("");
|
||||||
const exitCode = (await compileExec.inspect()).ExitCode;
|
const exitCode = (await compileExec.inspect()).ExitCode;
|
||||||
|
|
||||||
let result: JudgeResult;
|
let result: JudgeResultMetadata;
|
||||||
|
|
||||||
if (exitCode !== 0 || stderr) {
|
if (exitCode !== 0 || stderr) {
|
||||||
result = { output: stderr || "Compilation Error", exitCode: ExitCode.CE };
|
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
|
// 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({
|
const runExec = await container.exec({
|
||||||
Cmd: [`./${fileName}`],
|
Cmd: [`./${fileName}`],
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Promise<JudgeResult>((resolve, reject) => {
|
return new Promise<JudgeResultMetadata>((resolve, reject) => {
|
||||||
const stdoutChunks: string[] = [];
|
const stdoutChunks: string[] = [];
|
||||||
let stdoutLength = 0;
|
let stdoutLength = 0;
|
||||||
const stdoutStream = new Writable({
|
const stdoutStream = new Writable({
|
||||||
@ -211,7 +214,7 @@ async function run(container: Docker.Container, fileName: string, timeLimit?: nu
|
|||||||
const stderr = stderrChunks.join("");
|
const stderr = stderrChunks.join("");
|
||||||
const exitCode = (await runExec.inspect()).ExitCode;
|
const exitCode = (await runExec.inspect()).ExitCode;
|
||||||
|
|
||||||
let result: JudgeResult;
|
let result: JudgeResultMetadata;
|
||||||
|
|
||||||
// Exit code 0 means successful execution
|
// Exit code 0 means successful execution
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
|
@ -1,42 +1,9 @@
|
|||||||
// Result type definitions
|
import { EditorLanguage } from "@/types/editor-language";
|
||||||
export enum ExitCode {
|
import { EditorLanguageConfig } from "./editor-language";
|
||||||
SE = 0, // System Error
|
import { DockerMetadata, JudgeMetadata } from "@/types/judge";
|
||||||
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 JudgeResult = {
|
export const DockerConfig: Record<EditorLanguage, DockerMetadata> = {
|
||||||
output: string;
|
[EditorLanguage.C]: {
|
||||||
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",
|
|
||||||
image: "gcc",
|
image: "gcc",
|
||||||
tag: "latest",
|
tag: "latest",
|
||||||
workingDir: "/src",
|
workingDir: "/src",
|
||||||
@ -45,11 +12,7 @@ export const LanguageConfigs: Record<string, LanguageConfig> = {
|
|||||||
compileOutputLimit: 1 * 1024 * 1024,
|
compileOutputLimit: 1 * 1024 * 1024,
|
||||||
runOutputLimit: 1 * 1024 * 1024,
|
runOutputLimit: 1 * 1024 * 1024,
|
||||||
},
|
},
|
||||||
cpp: {
|
[EditorLanguage.CPP]: {
|
||||||
id: "cpp",
|
|
||||||
label: "C++",
|
|
||||||
fileName: "main",
|
|
||||||
fileExtension: "cpp",
|
|
||||||
image: "gcc",
|
image: "gcc",
|
||||||
tag: "latest",
|
tag: "latest",
|
||||||
workingDir: "/src",
|
workingDir: "/src",
|
||||||
@ -57,5 +20,16 @@ export const LanguageConfigs: Record<string, LanguageConfig> = {
|
|||||||
memoryLimit: 128,
|
memoryLimit: 128,
|
||||||
compileOutputLimit: 1 * 1024 * 1024,
|
compileOutputLimit: 1 * 1024 * 1024,
|
||||||
runOutputLimit: 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
35
src/types/judge.ts
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user