"use server"; import Dockerode from "dockerode"; import { pullImage } from "@/actions/docker/image"; import { MessageType, MessageProps, } from "@/app/playground/layout/terminal/components/message"; 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); } } function mapResultTypeToMessageType(type: ResultType): MessageType { switch (type) { case ResultType.CompilationError: case ResultType.RuntimeError: return "error"; case ResultType.Success: return "success"; default: return "info"; } } 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, }); const result = await getOutputAndResultType(stream); return { type: mapResultTypeToMessageType(result.type), message: result.message, }; } else { throw new Error(`不支持的语言: ${language}`); } } catch (error) { console.error("运行代码时出错:", error); return { type: "error", message: error instanceof Error ? error.message : "未知错误", }; } finally { if (container) { await cleanupContainer(container); } } }