Skip to content

Commit 542f9bb

Browse files
committed
Add javascript execution
1 parent bd95eb0 commit 542f9bb

File tree

7 files changed

+108
-39
lines changed

7 files changed

+108
-39
lines changed

apps/docker-compose.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@ services:
129129
- apps_network
130130
container_name: python-sandbox
131131

132+
node-sandbox:
133+
build:
134+
context: ./execution-service/execution/node
135+
dockerfile: Dockerfile
136+
networks:
137+
- apps_network
138+
container_name: node-sandbox
139+
stdin_open: true # Enables interactive mode for passing standard input
140+
132141
networks:
133142
apps_network:
134143

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package constants
22

33
const (
4-
JAVA = "Java"
5-
PYTHON = "Python"
6-
GOLANG = "Golang"
7-
JAVASCRIPT = "Javascript"
8-
CPP = "C++"
4+
JAVA = "java"
5+
PYTHON = "python"
6+
GOLANG = "golang"
7+
JAVASCRIPT = "javascript"
8+
CPP = "c++"
99
)
1010

1111
const (
@@ -17,6 +17,6 @@ var IS_VALID_LANGUAGE = map[string]bool{
1717
PYTHON: true,
1818
//JAVA: true,
1919
//GOLANG: true,
20-
//JAVASCRIPT: true,
20+
JAVASCRIPT: true,
2121
//CPP: true,
2222
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Use a slim Node.js image
2+
FROM node:18-slim
3+
4+
# Set the working directory
5+
WORKDIR /app
6+
7+
# Install any dependencies if necessary (you can skip if no dependencies)
8+
# COPY package*.json ./
9+
# RUN npm install
10+
11+
# No entry point or CMD needed as you'll provide the command at runtime
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package node
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"os/exec"
7+
"strings"
8+
)
9+
10+
func RunJavaScriptCode(code string, input string) (string, string, error) {
11+
cmd := exec.Command(
12+
"docker", "run", "--rm",
13+
"-i", // allows standard input to be passed in
14+
"apps-node-sandbox", // Docker image with Node.js environment
15+
"node", "-e", code, // Runs JavaScript code with Node.js
16+
)
17+
18+
// Pass input to the JavaScript script
19+
cmd.Stdin = bytes.NewBufferString(input)
20+
21+
// Capture standard output and error output
22+
var output bytes.Buffer
23+
var errorOutput bytes.Buffer
24+
cmd.Stdout = &output
25+
cmd.Stderr = &errorOutput
26+
27+
// Run the command
28+
if err := cmd.Run(); err != nil {
29+
return "", fmt.Sprintf("Command execution failed: %s: %v", errorOutput.String(), err), nil
30+
}
31+
32+
return strings.TrimSuffix(output.String(), "\n"), strings.TrimSuffix(errorOutput.String(), "\n"), nil
33+
}

apps/execution-service/utils/executeTest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package utils
22

33
import (
44
"execution-service/constants"
5+
"execution-service/execution/node"
56
"execution-service/execution/python"
67
"execution-service/models"
78
"fmt"
@@ -15,6 +16,8 @@ func ExecuteVisibleAndCustomTests(code models.Code, test models.Test) (models.Ex
1516
case constants.PYTHON:
1617
testResults, err = getVisibleAndCustomTestResults(code, test, python.RunPythonCode)
1718
break
19+
case constants.JAVASCRIPT:
20+
testResults, err = getVisibleAndCustomTestResults(code, test, node.RunJavaScriptCode)
1821
default:
1922
return models.ExecutionResults{}, fmt.Errorf("unsupported language: %s", code.Language)
2023
}
@@ -33,6 +36,8 @@ func ExecuteVisibleAndHiddenTests(code models.Code, test models.Test) (models.Su
3336
case constants.PYTHON:
3437
testResults, err = getVisibleAndHiddenTestResults(code, test, python.RunPythonCode)
3538
break
39+
case constants.JAVASCRIPT:
40+
testResults, err = getVisibleAndHiddenTestResults(code, test, node.RunJavaScriptCode)
3641
default:
3742
return models.SubmissionResults{}, fmt.Errorf("unsupported language: %s", code.Language)
3843
}

apps/frontend/src/app/collaboration/[id]/page.tsx

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export default function CollaborationPage(props: CollaborationProps) {
7171
const [complexity, setComplexity] = useState<string | undefined>(undefined);
7272
const [categories, setCategories] = useState<string[]>([]); // Store the selected filter categories
7373
const [description, setDescription] = useState<string | undefined>(undefined);
74-
const [selectedLanguage, setSelectedLanguage] = useState("Python"); // State to hold the selected language item
74+
const [selectedLanguage, setSelectedLanguage] = useState("python"); // State to hold the selected language item
7575

7676
// Session states
7777
const [collaborationId, setCollaborationId] = useState<string | undefined>(
@@ -228,22 +228,29 @@ export default function CollaborationPage(props: CollaborationProps) {
228228
setVisibleTestCases(data.visibleTestResults);
229229
};
230230

231+
const updateLangauge = (data: string) => {
232+
setSelectedLanguage(data);
233+
}
234+
231235
const handleRunTestCases = async () => {
232236
if (!questionDocRefId) {
233237
throw new Error("Question ID not found");
234238
}
235239
setIsLoadingTestCase(true);
236240
sendExecutingStateToMatchedUser(true);
237-
const data = await ExecuteVisibleAndCustomTests(questionDocRefId, {
238-
code: code,
239-
language: selectedLanguage,
240-
customTestCases: "",
241-
});
242-
setVisibleTestCases(data.visibleTestResults);
243-
infoMessage("Test cases executed. Review the results below.");
244-
sendExecutionResultsToMatchedUser(data);
245-
setIsLoadingTestCase(false);
246-
sendExecutingStateToMatchedUser(false);
241+
try {
242+
const data = await ExecuteVisibleAndCustomTests(questionDocRefId, {
243+
code: code,
244+
language: selectedLanguage,
245+
customTestCases: "",
246+
});
247+
setVisibleTestCases(data.visibleTestResults);
248+
infoMessage("Test cases executed. Review the results below.");
249+
sendExecutionResultsToMatchedUser(data);
250+
} finally {
251+
setIsLoadingTestCase(false);
252+
sendExecutingStateToMatchedUser(false);
253+
}
247254
};
248255

249256
const handleSubmitCode = async () => {
@@ -252,25 +259,28 @@ export default function CollaborationPage(props: CollaborationProps) {
252259
}
253260
setIsLoadingSubmission(true);
254261
sendSubmittingStateToMatchedUser(true);
255-
const data = await ExecuteVisibleAndHiddenTestsAndSubmit(questionDocRefId, {
256-
code: code,
257-
language: selectedLanguage,
258-
user: currentUser ?? "",
259-
matchedUser: matchedUser ?? "",
260-
matchedTopics: matchedTopics ?? [],
261-
title: questionTitle ?? "",
262-
questionDifficulty: complexity ?? "",
263-
questionTopics: categories,
264-
});
265-
setVisibleTestCases(data.visibleTestResults);
266-
setSubmissionHiddenTestResultsAndStatus({
267-
hiddenTestResults: data.hiddenTestResults,
268-
status: data.status,
269-
});
270-
sendSubmissionResultsToMatchedUser(data);
271-
successMessage("Code saved successfully!");
272-
setIsLoadingSubmission(false);
273-
sendSubmittingStateToMatchedUser(false);
262+
try {
263+
const data = await ExecuteVisibleAndHiddenTestsAndSubmit(questionDocRefId, {
264+
code: code,
265+
language: selectedLanguage,
266+
user: currentUser ?? "",
267+
matchedUser: matchedUser ?? "",
268+
matchedTopics: matchedTopics ?? [],
269+
title: questionTitle ?? "",
270+
questionDifficulty: complexity ?? "",
271+
questionTopics: categories,
272+
});
273+
setVisibleTestCases(data.visibleTestResults);
274+
setSubmissionHiddenTestResultsAndStatus({
275+
hiddenTestResults: data.hiddenTestResults,
276+
status: data.status,
277+
});
278+
sendSubmissionResultsToMatchedUser(data);
279+
successMessage("Code saved successfully!");
280+
} finally {
281+
setIsLoadingSubmission(false);
282+
sendSubmittingStateToMatchedUser(false);
283+
}
274284
};
275285

276286
const handleCodeChange = (code: string) => {
@@ -492,7 +502,7 @@ export default function CollaborationPage(props: CollaborationProps) {
492502
ref={editorRef}
493503
user={currentUser}
494504
collaborationId={collaborationId}
495-
language={selectedLanguage}
505+
updateLanguage={updateLangauge}
496506
setMatchedUser={setMatchedUser}
497507
handleCloseCollaboration={handleCloseCollaboration}
498508
providerRef={providerRef}

apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { ExecutionResults, SubmissionResults } from "@/app/services/execute";
3232
interface CollaborativeEditorProps {
3333
user: string;
3434
collaborationId: string;
35-
language: string;
35+
updateLanguage: (language: string) => void;
3636
setMatchedUser: Dispatch<SetStateAction<string>>;
3737
handleCloseCollaboration: (type: string) => void;
3838
providerRef: MutableRefObject<WebrtcProvider | null>;
@@ -203,6 +203,7 @@ const CollaborativeEditor = forwardRef(
203203
language: selectedLanguage,
204204
id: latestLanguageChangeId,
205205
});
206+
props.updateLanguage(selectedLanguage);
206207
success(`Changed Code Editor's language to ${selectedLanguage}`);
207208
} else {
208209
setMounted(true);
@@ -385,7 +386,7 @@ const CollaborativeEditor = forwardRef(
385386
extensions: [
386387
basicSetup,
387388
languageConf.of(python()),
388-
// languageConf.of(javascript()),
389+
// languageConf.of(node()),
389390
autoLanguage,
390391
yCollab(ytext, provider.awareness, { undoManager }),
391392
keymap.of([indentWithTab]),

0 commit comments

Comments
 (0)