Skip to content

Commit

Permalink
Merge pull request #88 from CS3219-AY2425S1/solomon/add-execute-javas…
Browse files Browse the repository at this point in the history
…cript

feat: n4 add javascript execution
  • Loading branch information
tituschewxj authored Nov 13, 2024
2 parents abf4605 + e23725b commit bb8cc46
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 39 deletions.
9 changes: 9 additions & 0 deletions apps/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ services:
- apps_network
container_name: python-sandbox

node-sandbox:
build:
context: ./execution-service/execution/node
dockerfile: Dockerfile
networks:
- apps_network
container_name: node-sandbox
stdin_open: true # Enables interactive mode for passing standard input

networks:
apps_network:

Expand Down
12 changes: 6 additions & 6 deletions apps/execution-service/constants/constant.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package constants

const (
JAVA = "Java"
PYTHON = "Python"
GOLANG = "Golang"
JAVASCRIPT = "Javascript"
CPP = "C++"
JAVA = "java"
PYTHON = "python"
GOLANG = "golang"
JAVASCRIPT = "javascript"
CPP = "c++"
)

const (
Expand All @@ -17,6 +17,6 @@ var IS_VALID_LANGUAGE = map[string]bool{
PYTHON: true,
//JAVA: true,
//GOLANG: true,
//JAVASCRIPT: true,
JAVASCRIPT: true,
//CPP: true,
}
11 changes: 11 additions & 0 deletions apps/execution-service/execution/node/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Use a slim Node.js image
FROM node:18-slim

# Set the working directory
WORKDIR /app

# Install any dependencies if necessary (you can skip if no dependencies)
# COPY package*.json ./
# RUN npm install

# No entry point or CMD needed as you'll provide the command at runtime
33 changes: 33 additions & 0 deletions apps/execution-service/execution/node/javascript.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package node

import (
"bytes"
"fmt"
"os/exec"
"strings"
)

func RunJavaScriptCode(code string, input string) (string, string, error) {
cmd := exec.Command(
"docker", "run", "--rm",
"-i", // allows standard input to be passed in
"apps-node-sandbox", // Docker image with Node.js environment
"node", "-e", code, // Runs JavaScript code with Node.js
)

// Pass input to the JavaScript script
cmd.Stdin = bytes.NewBufferString(input)

// Capture standard output and error output
var output bytes.Buffer
var errorOutput bytes.Buffer
cmd.Stdout = &output
cmd.Stderr = &errorOutput

// Run the command
if err := cmd.Run(); err != nil {
return "", fmt.Sprintf("Command execution failed: %s: %v", errorOutput.String(), err), nil
}

return strings.TrimSuffix(output.String(), "\n"), strings.TrimSuffix(errorOutput.String(), "\n"), nil
}
5 changes: 5 additions & 0 deletions apps/execution-service/utils/executeTest.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"execution-service/constants"
"execution-service/execution/node"
"execution-service/execution/python"
"execution-service/models"
"fmt"
Expand All @@ -15,6 +16,8 @@ func ExecuteVisibleAndCustomTests(code models.Code, test models.Test) (models.Ex
case constants.PYTHON:
testResults, err = getVisibleAndCustomTestResults(code, test, python.RunPythonCode)
break
case constants.JAVASCRIPT:
testResults, err = getVisibleAndCustomTestResults(code, test, node.RunJavaScriptCode)
default:
return models.ExecutionResults{}, fmt.Errorf("unsupported language: %s", code.Language)
}
Expand All @@ -33,6 +36,8 @@ func ExecuteVisibleAndHiddenTests(code models.Code, test models.Test) (models.Su
case constants.PYTHON:
testResults, err = getVisibleAndHiddenTestResults(code, test, python.RunPythonCode)
break
case constants.JAVASCRIPT:
testResults, err = getVisibleAndHiddenTestResults(code, test, node.RunJavaScriptCode)
default:
return models.SubmissionResults{}, fmt.Errorf("unsupported language: %s", code.Language)
}
Expand Down
72 changes: 41 additions & 31 deletions apps/frontend/src/app/collaboration/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default function CollaborationPage(props: CollaborationProps) {
const [complexity, setComplexity] = useState<string | undefined>(undefined);
const [categories, setCategories] = useState<string[]>([]); // Store the selected filter categories
const [description, setDescription] = useState<string | undefined>(undefined);
const [selectedLanguage, setSelectedLanguage] = useState("Python"); // State to hold the selected language item
const [selectedLanguage, setSelectedLanguage] = useState("python"); // State to hold the selected language item

// Session states
const [collaborationId, setCollaborationId] = useState<string | undefined>(
Expand Down Expand Up @@ -232,22 +232,29 @@ export default function CollaborationPage(props: CollaborationProps) {
localStorage.setItem("visibleTestResults", JSON.stringify(data.visibleTestResults));
};

const updateLangauge = (data: string) => {
setSelectedLanguage(data);
}

const handleRunTestCases = async () => {
if (!questionDocRefId) {
throw new Error("Question ID not found");
}
setIsLoadingTestCase(true);
sendExecutingStateToMatchedUser(true);
const data = await ExecuteVisibleAndCustomTests(questionDocRefId, {
code: code,
language: selectedLanguage,
customTestCases: "",
});
updateExecutionResults(data);
infoMessage("Test cases executed. Review the results below.");
sendExecutionResultsToMatchedUser(data);
setIsLoadingTestCase(false);
sendExecutingStateToMatchedUser(false);
try {
const data = await ExecuteVisibleAndCustomTests(questionDocRefId, {
code: code,
language: selectedLanguage,
customTestCases: "",
});
updateExecutionResults(data);
infoMessage("Test cases executed. Review the results below.");
sendExecutionResultsToMatchedUser(data);
} finally {
setIsLoadingTestCase(false);
sendExecutingStateToMatchedUser(false);
}
};

const handleSubmitCode = async () => {
Expand All @@ -256,25 +263,28 @@ export default function CollaborationPage(props: CollaborationProps) {
}
setIsLoadingSubmission(true);
sendSubmittingStateToMatchedUser(true);
const data = await ExecuteVisibleAndHiddenTestsAndSubmit(questionDocRefId, {
code: code,
language: selectedLanguage,
user: currentUser ?? "",
matchedUser: matchedUser ?? "",
matchedTopics: matchedTopics ?? [],
title: questionTitle ?? "",
questionDifficulty: complexity ?? "",
questionTopics: categories,
});
updateExecutionResults({
visibleTestResults: data.visibleTestResults,
customTestResults: [],
});
updateSubmissionResults(data);
sendSubmissionResultsToMatchedUser(data);
successMessage("Code saved successfully!");
setIsLoadingSubmission(false);
sendSubmittingStateToMatchedUser(false);
try {
const data = await ExecuteVisibleAndHiddenTestsAndSubmit(questionDocRefId, {
code: code,
language: selectedLanguage,
user: currentUser ?? "",
matchedUser: matchedUser ?? "",
matchedTopics: matchedTopics ?? [],
title: questionTitle ?? "",
questionDifficulty: complexity ?? "",
questionTopics: categories,
});
updateExecutionResults({
visibleTestResults: data.visibleTestResults,
customTestResults: [],
});
updateSubmissionResults(data);
sendSubmissionResultsToMatchedUser(data);
successMessage("Code saved successfully!");
} finally {
setIsLoadingSubmission(false);
sendSubmittingStateToMatchedUser(false);
}
};

const handleCodeChange = (code: string) => {
Expand Down Expand Up @@ -505,7 +515,7 @@ export default function CollaborationPage(props: CollaborationProps) {
ref={editorRef}
user={currentUser}
collaborationId={collaborationId}
language={selectedLanguage}
updateLanguage={updateLangauge}
setMatchedUser={setMatchedUser}
handleCloseCollaboration={handleCloseCollaboration}
providerRef={providerRef}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { ExecutionResults, SubmissionResults } from "@/app/services/execute";
interface CollaborativeEditorProps {
user: string;
collaborationId: string;
language: string;
updateLanguage: (language: string) => void;
setMatchedUser: Dispatch<SetStateAction<string>>;
handleCloseCollaboration: (type: string) => void;
providerRef: MutableRefObject<WebrtcProvider | null>;
Expand Down Expand Up @@ -203,6 +203,7 @@ const CollaborativeEditor = forwardRef(
language: selectedLanguage,
id: latestLanguageChangeId,
});
props.updateLanguage(selectedLanguage);
success(`Changed Code Editor's language to ${selectedLanguage}`);
} else {
setMounted(true);
Expand Down Expand Up @@ -385,7 +386,7 @@ const CollaborativeEditor = forwardRef(
extensions: [
basicSetup,
languageConf.of(python()),
// languageConf.of(javascript()),
// languageConf.of(node()),
autoLanguage,
yCollab(ytext, provider.awareness, { undoManager }),
keymap.of([indentWithTab]),
Expand Down

0 comments on commit bb8cc46

Please sign in to comment.