diff --git a/src/app/actions/judge.ts b/src/app/actions/judge.ts index 463e4cf..715051b 100644 --- a/src/app/actions/judge.ts +++ b/src/app/actions/judge.ts @@ -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 { - const { fileName, fileExtension, image, tag, workingDir, memoryLimit, timeLimit, compileOutputLimit, runOutputLimit } = LanguageConfigs[language]; +): Promise { + 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 { +async function compile(container: Docker.Container, file: string, fileName: string, maxOutput: number = 1 * 1024 * 1024): Promise { const compileExec = await container.exec({ Cmd: ["gcc", "-O2", file, "-o", fileName], AttachStdout: true, AttachStderr: true, }); - return new Promise((resolve, reject) => { + return new Promise((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 { +async function run(container: Docker.Container, fileName: string, timeLimit?: number, maxOutput: number = 1 * 1024 * 1024): Promise { const runExec = await container.exec({ Cmd: [`./${fileName}`], AttachStdout: true, AttachStderr: true, }); - return new Promise((resolve, reject) => { + return new Promise((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) { diff --git a/src/config/judge.ts b/src/config/judge.ts index cfc66bf..33969fd 100644 --- a/src/config/judge.ts +++ b/src/config/judge.ts @@ -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 = { - c: { - id: "c", - label: "C", - fileName: "main", - fileExtension: "c", +export const DockerConfig: Record = { + [EditorLanguage.C]: { image: "gcc", tag: "latest", workingDir: "/src", @@ -45,11 +12,7 @@ export const LanguageConfigs: Record = { 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 = { memoryLimit: 128, compileOutputLimit: 1 * 1024 * 1024, runOutputLimit: 1 * 1024 * 1024, + } +} + +export const JudgeConfig: Record = { + [EditorLanguage.C]: { + editorLanguageMetadata: EditorLanguageConfig[EditorLanguage.C], + dockerMetadata: DockerConfig[EditorLanguage.C], + }, + [EditorLanguage.CPP]: { + editorLanguageMetadata: EditorLanguageConfig[EditorLanguage.CPP], + dockerMetadata: DockerConfig[EditorLanguage.CPP], }, }; diff --git a/src/types/judge.ts b/src/types/judge.ts new file mode 100644 index 0000000..29de9f1 --- /dev/null +++ b/src/types/judge.ts @@ -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; +}