Skip to content

Commit 3efd33a

Browse files
committed
Codeplayer Open Source Init
Signed-off-by: Saurabh Srivastava <saurabhsrivastava312@gmail.com>
0 parents  commit 3efd33a

File tree

107 files changed

+40595
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+40595
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.git
2+
.env
3+
.gitignore
4+
Dockerfile.*
5+
Dockerfile
6+
__pychache__
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__pycache__
2+
.env
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import boto3
2+
import os
3+
from compilerinfo import compiler_info
4+
import epicbox
5+
import urllib.request
6+
from dotenv import load_dotenv
7+
load_dotenv()
8+
9+
10+
class Compiler:
11+
__instance = None
12+
compiler_info = None
13+
PROFILES = None
14+
s3 = None
15+
memorylimit = 256
16+
timelimit = 5
17+
18+
def __init__(self):
19+
Compiler.__instance = self
20+
self.s3 = boto3.client(
21+
's3',
22+
aws_access_key_id=os.getenv('AWS_IAM_KEY'),
23+
aws_secret_access_key=os.getenv('AWS_IAM_SECRET')
24+
)
25+
26+
@staticmethod
27+
def getInstance():
28+
if Compiler.__instance == None:
29+
Compiler()
30+
return Compiler.__instance
31+
32+
def setCompilerLang(self, code_lang):
33+
self.compiler_info = compiler_info[code_lang]
34+
35+
def setCompilerMemoryLimit(self, memorylimit):
36+
self.memorylimit = memorylimit
37+
38+
def setCompilerTimeLimit(self, timelimit):
39+
self.timelimit = timelimit
40+
41+
def makeProfiles(self, user = "sandbox"):
42+
self.PROFILES = {
43+
'compile': {
44+
'docker_image': self.compiler_info['docker_image'],
45+
'user': 'root',
46+
},
47+
'run': {
48+
'docker_image': self.compiler_info['docker_image'],
49+
'user': user,
50+
'read_only': True,
51+
'network_disabled': False
52+
},
53+
'directRun': {
54+
'docker_image': self.compiler_info['docker_image']
55+
}
56+
}
57+
epicbox.configure(profiles=self.PROFILES)
58+
59+
def compile(self, work_dir, untrusted_code):
60+
return epicbox.run('compile', self.compiler_info["compile_cmd"],
61+
files=[{'name': 'solution.cpp',
62+
'content': self.readFile(untrusted_code)}],
63+
limits={'cputime': 60, 'memory': 2048},
64+
workdir=work_dir)
65+
66+
def run(self, work_dir, testcase):
67+
return epicbox.run('run', self.compiler_info["run_cmd"], stdin=self.readFile(testcase),
68+
limits={'cputime': self.timelimit, 'memory': self.memorylimit},
69+
workdir=work_dir)
70+
71+
def directRun(self, untrusted_code, testcase):
72+
return epicbox.run('directRun', self.compiler_info["run_cmd"], stdin=self.readFile(testcase),
73+
files=[{'name': 'solution.py',
74+
'content': self.readFile(untrusted_code)}],
75+
limits={'cputime': self.timelimit, 'memory': self.memorylimit})
76+
77+
def readFile(self, file_link):
78+
data = self.s3.get_object(
79+
Bucket=os.getenv("AWS_S3_BUCKET"), Key=file_link)
80+
return data["Body"].read()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM python:3
2+
WORKDIR /codeplayer_worker
3+
COPY ./requirements.txt .
4+
RUN pip3 install -r requirements.txt
5+
COPY . .
6+
CMD ["python3", "./test.py"]
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
compiler_info = {
2+
"c++": {
3+
"docker_image": "stepik/epicbox-gcc:6.3.0",
4+
"compile_cmd": "g++ -pipe -static -O2 -std=c++14 -w solution.cpp -o solution",
5+
"run_cmd": "./solution",
6+
},
7+
"python": {
8+
"docker_image": "python:3.6.5-alpine",
9+
"compile_cmd": "NA",
10+
"run_cmd": "python3 ./solution.py",
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
REDISHOST=REDIS_HOST
2+
3+
AWS_IAM_KEY=AWS_IAM_KEY
4+
AWS_IAM_SECRET=AWS_IAM_SECRET
5+
6+
AWS_S3_BUCKET=AWS_BUCKET_NAME
7+
8+
APP_SERVER=SERVER_HOST
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
epicbox
2+
PyRSMQ
3+
boto3
4+
python-dotenv
5+
python-socketio
6+
simplejson
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from worker import Worker
2+
3+
work = Worker()
4+
work.boot()
+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import boto3
2+
import os
3+
from Compiler import Compiler
4+
import epicbox
5+
import socketio
6+
import urllib.request
7+
from rsmq.consumer import RedisSMQConsumer
8+
import simplejson as json
9+
import requests
10+
from dotenv import load_dotenv
11+
load_dotenv()
12+
import ast
13+
14+
15+
class Worker:
16+
# To be initailized in constructor
17+
compiler = None
18+
inputs = None
19+
outputs = None
20+
untrusted_code = None
21+
code_lang = None
22+
redis_consumer = None
23+
s3 = None
24+
sio = None
25+
user_id = None
26+
submission_id = None
27+
memorylimit = 256
28+
timelimit = 5
29+
30+
# Will be called when new worker in initialized
31+
def __init__(self):
32+
self.compiler = Compiler.getInstance()
33+
self.s3 = boto3.client(
34+
's3',
35+
aws_access_key_id=os.getenv('AWS_IAM_KEY'),
36+
aws_secret_access_key=os.getenv('AWS_IAM_SECRET')
37+
)
38+
# connect to socket server
39+
self.sio = socketio.Client()
40+
self.sio.connect(os.getenv("APP_SERVER"))
41+
42+
# call this to inititalize This Worker
43+
def boot(self):
44+
self.redis_consumer = RedisSMQConsumer(
45+
'submissions', self.fetchResourcesAndProcess, host=os.getenv("REDISHOST"))
46+
self.redis_consumer.run()
47+
48+
# Fetch inputs (Array of links), outputs (Array of links), untrusted_code (link to the code)
49+
def fetchResourcesAndProcess(self, id, message, rc, ts):
50+
51+
# we get only submission ID from queue
52+
queuedata = message.split("::")
53+
print(queuedata)
54+
55+
self.user_id = queuedata[0]
56+
self.submission_id = queuedata[1]
57+
58+
self.sio.emit("joinroom", self.user_id)
59+
60+
# we request api server
61+
ques_details_response = requests.get(
62+
os.getenv("APP_SERVER") + '/worker/testdata/' + self.submission_id)
63+
ques_data = json.loads(ques_details_response.text)
64+
65+
self.inputs = ques_data['inputs']
66+
self.outputs = ques_data['outputs']
67+
self.code_lang = ques_data['lang']
68+
self.untrusted_code = ques_data['code']
69+
self.memorylimit = ques_data['memorylimit']
70+
self.timelimit = ques_data['timelimit']
71+
72+
self.compilerInitialSetup()
73+
74+
if(self.code_lang == "c++"):
75+
self.processCompileAndRun()
76+
elif(self.code_lang == "python"):
77+
self.processDirectRun()
78+
else:
79+
self.pingMessage({error: "LR", message: "Language Rejected"})
80+
81+
self.sio.emit("leaveroom", self.user_id)
82+
return True
83+
84+
# Perform some initial setup for compiler
85+
def compilerInitialSetup(self):
86+
self.compiler.setCompilerLang(self.code_lang)
87+
self.compiler.setCompilerMemoryLimit(self.memorylimit)
88+
self.compiler.setCompilerTimeLimit(self.timelimit)
89+
self.compiler.makeProfiles()
90+
91+
92+
# Use this when required to compile first and then execute like in C++ and Java
93+
def processCompileAndRun(self):
94+
with epicbox.working_directory() as working_dir:
95+
self.pingMessage(
96+
{"success": "CMPL", "message": "Compiling your code"})
97+
compile_result = self.compiler.compile(
98+
working_dir, self.untrusted_code)
99+
if(compile_result["exit_code"] != 0):
100+
return self.pingMessage({"error": "CE", "message": compile_result["stderr"]})
101+
self.pingMessage(
102+
{"success": "CMPLS", "message": "Compilation Success"})
103+
104+
testcase_number = 0
105+
for input in self.inputs:
106+
testcase_number = testcase_number + 1
107+
108+
self.pingMessage(
109+
{"success": "RUN", "message": "Running on testcase #" + str(testcase_number)})
110+
run_result = self.compiler.run(working_dir, input)
111+
112+
if(run_result["oom_killed"] or run_result["timeout"] or run_result["exit_code"]):
113+
return self.pingRunError(run_result, testcase_number)
114+
115+
print(run_result)
116+
eval_result = self.matchOutput(
117+
run_result["stdout"], self.outputs[testcase_number - 1])
118+
if(eval_result == False):
119+
return self.pingMessage({"error": "WA", "message": "Wrong answer on testcase #" + str(testcase_number)})
120+
121+
self.pingMessage(
122+
{"success": "ACS", "message": "Correct on testcase #" + str(testcase_number)})
123+
124+
return self.pingMessage({"success": "AC", "message": "Accepted Solution"})
125+
126+
# Use this for languages where we can direct run the code like python
127+
def processDirectRun(self):
128+
self.pingMessage(
129+
{"success": "CMPL", "message": "Evaluating Your Code"})
130+
131+
testcase_number = 0
132+
for input in self.inputs:
133+
testcase_number = testcase_number + 1
134+
135+
self.pingMessage(
136+
{"success": "RUN", "message": "Running on testcase #" + str(testcase_number)})
137+
run_result = self.compiler.directRun(self.untrusted_code, input)
138+
139+
if(run_result["oom_killed"] or run_result["timeout"] or run_result["exit_code"]):
140+
return self.pingRunError(run_result, testcase_number)
141+
142+
print(run_result)
143+
eval_result = self.matchOutput(
144+
run_result["stdout"], self.outputs[testcase_number - 1])
145+
if(eval_result == False):
146+
return self.pingMessage({"error": "WA", "message": "Wrong answer on testcase #" + str(testcase_number)})
147+
148+
self.pingMessage(
149+
{"success": "ACS", "message": "Correct on testcase #" + str(testcase_number)})
150+
151+
return self.pingMessage({"success": "AC", "message": "Accepted Solution"})
152+
153+
def matchOutput(self, user_output, expected_output):
154+
user_output = user_output.strip()
155+
expected_output = self.readFile(expected_output).strip()
156+
if(user_output == expected_output):
157+
return True
158+
return False
159+
160+
def pingRunError(self, run_result, testcase_number):
161+
print(run_result)
162+
if((run_result["timeout"] and run_result["duration"] > self.timelimit + 1) or run_result["oom_killed"]):
163+
return self.pingMessage({"error": "MLE", "message": "Memory Limit Exceed on testcase #" + str(testcase_number)})
164+
elif(run_result["timeout"]):
165+
return self.pingMessage({"error": "TLE", "message": "Time Limit Exceed on testcase #" + str(testcase_number)})
166+
else:
167+
return self.pingMessage({"error": "RE", "message": "Run Time Error on testcase #" + str(testcase_number)})
168+
169+
def pingMessage(self, message):
170+
message["userId"] = self.user_id
171+
message["submissionId"] = self.submission_id
172+
self.sio.emit("status", json.dumps(message))
173+
# print(message)
174+
return True
175+
176+
def readFile(self, file_link):
177+
data = self.s3.get_object(
178+
Bucket=os.getenv("AWS_S3_BUCKET"), Key=file_link)
179+
return data["Body"].read()

codeplayer-frontend/.dockerignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.git
2+
node_modules
3+
npm-debug.log
4+
.gitignore
5+
*.md

codeplayer-frontend/.gitignore

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*

codeplayer-frontend/Dockerfile

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM node:12.16.1-alpine3.9 as build
2+
3+
MAINTAINER Saurabh Srivastava (saurass.in)
4+
5+
WORKDIR /codeplayer_frontend
6+
COPY package*.json /codeplayer_frontend/
7+
RUN yarn
8+
COPY . /codeplayer_frontend
9+
RUN yarn build
10+
11+
FROM nginx:alpine
12+
13+
MAINTAINER Saurabh Srivastava (saurass.in)
14+
15+
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
16+
COPY --from=build /codeplayer_frontend/build /usr/share/nginx/html
17+
EXPOSE 80
18+
CMD ["nginx", "-g", "daemon off;"]

codeplayer-frontend/example.env

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
REACT_APP_BACKEND=API_SERVER_HOST
2+
REACT_APP_SOCKETIO_SERVER=SOCKETIO_SERVER_HOST
3+
REACT_APP_RAZORPAY_API_ID=RAZOR_PAY_KEY_ID
4+
REACT_APP_RECAPTCHA_KEY=RECAPTCHA_KEY

0 commit comments

Comments
 (0)