diff --git a/src/actions/docker/compile.ts b/src/actions/docker/compile.ts deleted file mode 100644 index baa7436..0000000 --- a/src/actions/docker/compile.ts +++ /dev/null @@ -1,90 +0,0 @@ -"use server"; - -import Dockerode from "dockerode"; -import { pullImage } from "./image"; - -export async function runCode(code: string, language: string) { - const docker = new Dockerode({ socketPath: "/var/run/docker.sock" }); - let container; - - try { - if (language === "c") { - const imageGCC = "gcc:latest"; - const images = await docker.listImages(); - const image = images.find( - (image) => image.RepoTags && image.RepoTags.includes(imageGCC) - ); - if (!image) { - await pullImage(imageGCC); - } - - container = await docker.createContainer({ - Image: imageGCC, - Cmd: [ - "sh", - "-c", - `export LANG=C.UTF-8 && printf '%s' '${code.replace( - /'/g, - "'\\''" - )}' > main.c && gcc main.c -o main && ./main`, - ], - Tty: false, - }); - - await container.start(); - - const stream = await container.attach({ - stream: true, - stdout: true, - stderr: true, - }); - - const output = await new Promise((resolve, reject) => { - let output = ""; - stream.on("data", (chunk) => { - output += chunk.toString("utf8"); - }); - stream.on("end", () => { - resolve(output); - }); - stream.on("error", (err) => { - reject(err); - }); - }); - - console.log("Output:", output); - - // 检查输出中是否有错误信息 - const isCompilationSuccess = !output.includes("error:"); - - return { - success: isCompilationSuccess, - output: output, - message: isCompilationSuccess - ? "Compilation successful" - : "Compilation failed", - }; - } else { - throw new Error(`Unsupported language: ${language}`); - } - } catch (error) { - console.error("Error running code:", error); - return { - success: false, - output: error instanceof Error ? error.message : "Unknown error", - message: "Compilation failed", - }; - } finally { - if (container) { - try { - const containerInfo = await container.inspect(); - if (containerInfo.State.Running) { - await container.stop(); - } - await container.remove(); - } catch (cleanupError) { - console.error("Error cleaning up container:", cleanupError); - } - } - } -} diff --git a/src/actions/docker/run.ts b/src/actions/docker/run.ts new file mode 100644 index 0000000..b041d59 --- /dev/null +++ b/src/actions/docker/run.ts @@ -0,0 +1,126 @@ +"use server"; + +import Dockerode from "dockerode"; +import { pullImage } from "@/actions/docker/image"; + +enum ResultType { + CompilationError = "compilation error", + RuntimeError = "runtime error", + Success = "success", +} + +interface RunCodeResult { + success: boolean; + output: string; + message: string; + type: ResultType; +} + +async function prepareEnvironment(docker: Dockerode, imageGCC: string) { + const images = await docker.listImages(); + const imageExists = images.some( + (image) => image.RepoTags && image.RepoTags.includes(imageGCC) + ); + + if (!imageExists) { + await pullImage(imageGCC); + } +} + +async function compileAndRun( + code: string, + docker: Dockerode, + imageGCC: string +): Promise { + const container = await docker.createContainer({ + Image: imageGCC, + Cmd: [ + "sh", + "-c", + `export LANG=C.UTF-8 && printf '%s' '${code.replace( + /'/g, + "'\\''" + )}' > main.c && gcc main.c -o main && ./main`, + ], + Tty: false, + }); + + await container.start(); + return container; +} + +async function getOutputAndResultType( + stream: NodeJS.ReadableStream +): Promise { + return new Promise((resolve, reject) => { + let output = ""; + stream.on("data", (chunk) => { + output += chunk.toString("utf8"); + }); + stream.on("end", () => { + const isSuccessful = !output.includes("error:"); + const message = isSuccessful + ? "运行成功:编译成功" + : "运行错误:编译失败"; + + resolve({ + success: isSuccessful, + output, + message, + type: isSuccessful ? ResultType.Success : ResultType.CompilationError, + }); + }); + stream.on("error", (err) => { + reject(err); + }); + }); +} + +async function cleanupContainer(container: Dockerode.Container): Promise { + try { + const containerInfo = await container.inspect(); + if (containerInfo.State.Running) { + await container.stop(); + } + await container.remove(); + } catch (cleanupError) { + console.error("清理容器时出错:", cleanupError); + } +} + +export async function runCode( + language: string, + code: string +): Promise { + const docker = new Dockerode({ socketPath: "/var/run/docker.sock" }); + const imageGCC = "gcc:latest"; + let container: Dockerode.Container | undefined; + + try { + if (language === "c") { + await prepareEnvironment(docker, imageGCC); + container = await compileAndRun(code, docker, imageGCC); + const stream = await container.attach({ + stream: true, + stdout: true, + stderr: true, + }); + + return await getOutputAndResultType(stream); + } else { + throw new Error(`不支持的语言: ${language}`); + } + } catch (error) { + console.error("运行代码时出错:", error); + return { + success: false, + output: error instanceof Error ? error.message : "未知错误", + message: "运行错误:未知错误", + type: ResultType.RuntimeError, + }; + } finally { + if (container) { + await cleanupContainer(container); + } + } +}