Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added first API #9

Open
wants to merge 20 commits into
base: manish-poorvi
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
32 changes: 32 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
on:
release:
types: [created]

name: Deploy to Production

jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Push to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: poorvivaish/rce
tags: latest

- name: Setup key
id: setup-key
env:
EC2_KEY: ${{ secrets.EC2_KEY }}
run: |
echo "$EC2_KEY" >> $HOME/key.pem
chmod 400 $HOME/key.pem
- name: Update image on server
run: ssh -i $HOME/key.pem -o StrictHostKeyChecking=no [email protected] './deploy.sh'
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM node:12.18

WORKDIR /rce

RUN apt-get install python3 -y
RUN apt-get update && \
apt-get -y install gcc mono-mcs && \
rm -rf /var/lib/apt/lists/*

copy . .
RUN npm install
ENV PORT=8080
EXPOSE 8080

CMD [ "node", "index.js" ]
58 changes: 53 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,62 @@
# Remote-Code-Executor
RCE is a Remote Code Executor, as the name suggests Is a Docker-based sandbox environment to run a code snippet. It will create a new docker based container for every submitted code, run it in the isolated container, and return the output. It will support major languages C, C++, and can be extended to other language support too.
RCE is a Remote Code Executor, as the name suggests Is a Docker-based sandbox environment to run a code snippet. It will create a new file for each code input, execute it, delete the file and return the output. It supports major languages, i.e., C++, JavaScript and Python, and can be extended to other language support too.

# Features:
- Backend APIs and logic to handle the submitted code, create a docker container, execute it, and return the results.
- Minimal UI for user interaction and code submission.
- Backend APIs and logic to handle the submitted code, execute it, and return the results.
- Can be extended to an Online Code Judge and full-fledged coding/interview platform.

# Tech stack:
- Node.js
- Any Frontend framework or Basic HTML
- Javascript
- Docker
- Bash scripting.
- Bash scripting
- Nginx
- Github Actions

# Concepts Used
- Frontend and Backend were made separate for making it possible to scale them individually.
- exec function from `child-processes` package in NodeJS was used to execute programs.
- Application was containerized and is present on DockerHub, so that it can be used anywhere.
- Server has a Nginx Web Server front, for high performance and stability.
- HTTPS for the server was made possible by using Certbot and Lets Encrypt.
- Concepts of Functional Programming was used to make code more readable and modular.
- A CI/CD pipeline was setup using Github Actions for Quick Deployment.

# Steps to Run Locally
- Clone the Repo on your local computer
- Run `npm install` to install all the packages
```bash
npm install
```
- Run `npm start` to start the server locally
```bash
npm start
```
- Now you can view the server live at `http://localhost:3000`

# APIs
## `/execNode`, `/execCpp`, `execPython`
### Request Format
```json
{
"code": "console.log(\"Hello World\");"
}
```

### Response Format
```json
{
"isError": "true or false based on the code",
"output": "EXECUTION OUTPUT or ERROR",
"message": "Error Message if there was any"
}
```

# Basic Architecture
<img src="https://i.ibb.co/zbBg3xQ/Basic-Arch.png" alt="Basic Architecture" >

# CI/CD Flow
<img src="https://i.ibb.co/wM8CcgM/CI-CD-Flow.png" alt="CI CD Flow">

# Hosted Link
The server is hosted and live at [rce.manish.codes](https://rce.manish.codes)
58 changes: 41 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
const express = require("express");
const cors = require("cors");
const { execNode, execPython, execCpp } = require("./utils/executor");
const app = express();
const PORT = process.env.PORT || 3001;

//const { execute } = require("./utils/file-executor.js");
const {exec} = require("child_process");
const fs = require("fs");
app.use(express.json());
app.use(cors());
app.use(
express.urlencoded({
extended: true,
})
);
app.get("/", (req, res) => {
res.send("First server!!");
});
app.post("/execNode", async (req, res) => {
const data = req.body.code;
const input = req.body.input;
// console.log(data);
const output = await execNode(data, input || "");
console.log(output);
res.send(output);
});
app.post("/execPython", async (req, res) => {
const data = req.body.code;
const input = req.body.input;
// console.log(data);
const output = await execPython(data, input || "");
console.log(output);

const data = `console.log("Hello World!!!");`;
res.send(output);
});

fs.writeFile("temp/code.js", data, (err) => {
if (err) console.log(err);
else console.log("Successfully Written to File.");
exec("node temp/code.js", function(error, stdout, stderr) {
if (error) console.log(error);
console.log(stdout);
console.log(stderr);

fs.unlink("temp/code.js", () => {
console.log("File Deleted!!!")
});
});
app.post("/execCpp", async (req, res) => {
const data = req.body.code;
const input = req.body.input;
// console.log(data);
const output = await execCpp(data, input ||"");
console.log(output);
res.send(output);
});
app.listen(PORT, () => {
console.log("Server started!!");
});
// execute();
Loading