1- const express = require ( 'express' ) ;
2- const fs = require ( 'fs' ) . promises ;
3- const util = require ( 'util' ) ;
4- const exec = util . promisify ( require ( 'child_process' ) . exec ) ;
5- const path = require ( 'path' ) ;
6- const { v4 : uuidv4 } = require ( 'uuid' ) ;
7- const dotenv = require ( 'dotenv' ) ;
1+ import fileSystem from "fs" ;
2+ import express from "express" ;
3+ import dotenv from "dotenv" ;
4+ import { v4 as uuidv4 } from "uuid" ;
5+ import path from "path" ;
6+ import { promisify } from "util" ;
7+ import cors from "cors" ;
8+ import { LANGUAGE_CONFIG } from "./language/config.js" ;
9+ import { exec as executeProcess } from "child_process" ;
10+ import { allowOrigins } from "./origin/index.js" ;
11+ import { extractError } from "./utils/index.js" ;
12+ const exec = promisify ( executeProcess ) ;
13+ const fs = fileSystem . promises ;
814dotenv . config ( ) ;
915
1016const app = express ( ) ;
1117app . use ( express . json ( ) ) ;
12-
13- // Mapping of language to Docker image and main file name
14- const LANGUAGE_CONFIG = {
15- python : {
16- image : 'executor-python' ,
17- mainFile : 'main.py' ,
18- cmd : 'python main.py' , // Command to execute the main file
19- } ,
20- nodejs : {
21- image : 'executor-nodejs' ,
22- mainFile : 'index.js' ,
23- cmd : 'node index.js' ,
24- } ,
25- java : {
26- image : 'executor-java' ,
27- mainFile : 'Main.java' ,
28- cmd : 'sh -c "javac Main.java && java Main"' ,
29- } ,
30- } ;
18+ app . use (
19+ cors ( {
20+ origin : allowOrigins ,
21+ } )
22+ ) ;
3123
3224// which will be passed from docker-compose.yml
3325const HOST_PROJECT_ROOT = process . env . HOST_PROJECT_ROOT ;
26+ const directory_name = process . cwd ( ) ;
3427
35- app . post ( ' /run' , async ( req , res ) => {
28+ app . post ( " /run" , async ( req , res ) => {
3629 const { code, language } = req . body ;
3730
3831 if ( ! code || ! language ) {
3932 return res
4033 . status ( 400 )
41- . json ( { error : ' Code and language are required in the request body.' } ) ;
34+ . json ( { error : " Code and language are required in the request body." } ) ;
4235 }
4336
4437 const langConfig = LANGUAGE_CONFIG [ language ] ;
38+
4539 if ( ! langConfig )
4640 return res . status ( 400 ) . json ( { error : `Unsupported language: ${ language } ` } ) ;
4741
4842 // Generate a unique name for the temporary directory
4943 const tempDirName = uuidv4 ( ) ;
5044 // This is the path *inside the nodejs-server container* where the code will be written
51- const tempDirInsideNodeServer = path . join ( __dirname , 'temp' , tempDirName ) ;
45+ const tempDirInsideNodeServer = path . join (
46+ directory_name ,
47+ "temp" ,
48+ tempDirName
49+ ) ;
5250 const codeFilePath = path . join ( tempDirInsideNodeServer , langConfig . mainFile ) ;
5351
5452 // This is the absolute path *on the host machine* that corresponds to tempDirInsideNodeServer.
5553 // We use HOST_PROJECT_ROOT environment variable to construct this absolute path.
5654 if ( ! HOST_PROJECT_ROOT ) {
5755 console . error (
58- ' HOST_PROJECT_ROOT environment variable is not set. Volume mounts might fail.'
56+ " HOST_PROJECT_ROOT environment variable is not set. Volume mounts might fail."
5957 ) ;
6058 return res . status ( 500 ) . json ( {
61- error : ' Server configuration error' ,
59+ error : " Server configuration error" ,
6260 details :
63- "HOST_PROJECT_ROOT environment variable is missing. Please ensure it's set in docker-compose.yml." ,
61+ "HOST_PROJECT_ROOT environment variable is missing. Please ensure it's set in docker-compose.yaml." ,
62+ isDeveloper : true ,
6463 } ) ;
6564 }
66- const hostVolumePath = path . join ( HOST_PROJECT_ROOT , 'temp' , tempDirName ) ;
67-
68- console . log ( `[Executor] Request for ${ language } received.` ) ;
69- console . log (
70- `[Executor] tempDirInsideNodeServer (inside Node.js container): ${ tempDirInsideNodeServer } `
71- ) ;
72- console . log (
73- `[Executor] codeFilePath (inside Node.js container): ${ codeFilePath } `
74- ) ;
75- console . log ( `[Executor] HOST_PROJECT_ROOT (from env): ${ HOST_PROJECT_ROOT } ` ) ;
76- console . log (
77- `[Executor] hostVolumePath (for host Docker daemon): ${ hostVolumePath } `
78- ) ;
65+ const hostVolumePath = path . join ( HOST_PROJECT_ROOT , "temp" , tempDirName ) ;
7966
8067 try {
8168 // 1. Create the temporary directory inside the nodejs-server container
82- // (This directory will also appear on the host due to the volume mount configured in docker-compose.yml )
69+ // (This directory will also appear on the host due to the volume mount configured in docker-compose.yaml )
8370 await fs . mkdir ( tempDirInsideNodeServer , { recursive : true } ) ;
84- console . log (
85- `[Executor] Created temp directory: ${ tempDirInsideNodeServer } `
86- ) ;
8771
8872 // 2. Write the user's code to the temporary file
8973 await fs . writeFile ( codeFilePath , code ) ;
90- console . log ( `[Executor] Wrote code to: ${ codeFilePath } ` ) ;
9174
9275 // 3. Prepare and execute the Docker command
9376 // The -v flag uses the hostVolumePath (absolute path on host) as the source,
@@ -99,45 +82,26 @@ app.post('/run', async (req, res) => {
9982 const { stdout, stderr } = await exec ( runCommand ) ;
10083
10184 if ( stderr ) {
102- console . error (
103- `[Executor] Runtime error for ${ language } code in ${ tempDirInsideNodeServer } : ${ stderr } `
104- ) ;
10585 return res . status ( 500 ) . json ( {
106- error : ' Runtime error' ,
107- details : stderr ,
86+ error : " Runtime error" ,
87+ details : extractError ( stderr ) ,
10888 } ) ;
10989 }
11090 return res . status ( 200 ) . json ( {
11191 output : stdout ,
11292 } ) ;
11393 } catch ( err ) {
114- console . error ( `[Executor] Error processing request: ${ err . message } ` ) ;
11594 return res . status ( 500 ) . json ( {
116- error : ' Server error' ,
117- details : err . message ,
95+ error : "Internal Server error" ,
96+ details : extractError ( err . message ) ,
11897 } ) ;
11998 } finally {
120- // Ensure cleanup happens whether the execution was successful or an error occurred.
121- // This is a more robust way to ensure temp files are removed.
122- try {
123- await fs . rm ( tempDirInsideNodeServer , { recursive : true , force : true } ) ;
124- console . log (
125- `[Executor] Cleaned up temp directory: ${ tempDirInsideNodeServer } `
126- ) ;
127- } catch ( cleanupErr ) {
128- console . error (
129- `[Executor] Error cleaning up ${ tempDirInsideNodeServer } :` ,
130- cleanupErr
131- ) ;
132- }
99+ await fs . rm ( tempDirInsideNodeServer , { recursive : true , force : true } ) ;
133100 }
134101} ) ;
135102
136103// Use PORT from environment variables, or default to 6000
137- const PORT = process . env . PORT || 6000 ;
104+ const PORT = process . env . PORT || 5000 ;
138105app . listen ( PORT , ( ) => {
139106 console . log ( `Code executor backend listening on port ${ PORT } ` ) ;
140- console . log (
141- "Ensure your base Docker images (e.g., 'executor-python', 'executor-nodejs', 'executor-java') are pre-built."
142- ) ;
143107} ) ;
0 commit comments