diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..287a2f0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,162 @@
+### Python template
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/JetClient/state.xml b/.idea/JetClient/state.xml
new file mode 100644
index 0000000..cf4802b
--- /dev/null
+++ b/.idea/JetClient/state.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..4450099
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ redis
+ true
+ jdbc.RedisDriver
+ jdbc:redis://localhost:6379/0
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..ae51011
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..c026b2b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..89705fc
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/peetcode.iml b/.idea/peetcode.iml
new file mode 100644
index 0000000..26d44c7
--- /dev/null
+++ b/.idea/peetcode.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/src/Constants/Navbar/Navbar.jsx b/client/src/Constants/Navbar/Navbar.jsx
index 28ecfd1..e42f70e 100644
--- a/client/src/Constants/Navbar/Navbar.jsx
+++ b/client/src/Constants/Navbar/Navbar.jsx
@@ -9,7 +9,7 @@ const Navbar = () => {
@@ -25,4 +25,4 @@ const Navbar = () => {
)
}
-export default Navbar
+export default Navbar
\ No newline at end of file
diff --git a/client/src/constants.js b/client/src/constants.js
index 2a84056..08f307f 100644
--- a/client/src/constants.js
+++ b/client/src/constants.js
@@ -1 +1 @@
-export const backendUrl = "https://api.peetcode.com";
+export const backendUrl = "https://localhost:3000";
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..cae562a
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,55 @@
+version: "2.4" #pids_limit are not available in version 3 or higher
+
+services:
+ rabbitmq:
+ image: rabbitmq:3.11-management
+ restart: always
+# not necessary to expose ports, because they are already exposed in the image
+ ports:
+ - "5672:5672"
+ - "15672:15672"
+ networks:
+ - common
+ healthcheck:
+ test: ["CMD", "rabbitmqctl", "status"]
+ interval: 5s
+ timeout: 30s
+ retries: 3
+
+ redis:
+ image: redis
+ restart: always
+ networks:
+ - common
+ ports:
+ - "6379:6379"
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 5s
+ timeout: 30s
+ retries: 3
+
+ workers:
+ build:
+ context: ./workers
+ dockerfile: Dockerfile
+ environment:
+ - REDIS_HOST=redis
+ - REDIS_PORT=6379
+ - RABBITMQ_HOST=rabbitmq
+ depends_on:
+ rabbitmq:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ networks:
+ - common
+ pids_limit: 100
+ cpus: 0.5
+ mem_limit: 100m
+
+
+networks:
+ common:
+ driver: bridge
+
diff --git a/server/index.js b/server/index.js
index 9691a83..80b9fca 100644
--- a/server/index.js
+++ b/server/index.js
@@ -213,4 +213,4 @@ app.post("/login", (req, res) => {
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
-});
+});
\ No newline at end of file
diff --git a/server/package-lock.json b/server/package-lock.json
index 55cd30c..c23c4eb 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -9,10 +9,104 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
+ "amqplib": "^0.10.3",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.18.2",
- "jsonwebtoken": "^9.0.0"
+ "jsonwebtoken": "^9.0.0",
+ "redis": "^4.6.6"
+ }
+ },
+ "node_modules/@acuminous/bitsyntax": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz",
+ "integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==",
+ "dependencies": {
+ "buffer-more-ints": "~1.0.0",
+ "debug": "^4.3.4",
+ "safe-buffer": "~5.1.2"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/@acuminous/bitsyntax/node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@acuminous/bitsyntax/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/@acuminous/bitsyntax/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/@redis/bloom": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
+ "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
+ "peerDependencies": {
+ "@redis/client": "^1.0.0"
+ }
+ },
+ "node_modules/@redis/client": {
+ "version": "1.5.7",
+ "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz",
+ "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==",
+ "dependencies": {
+ "cluster-key-slot": "1.1.2",
+ "generic-pool": "3.9.0",
+ "yallist": "4.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@redis/graph": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz",
+ "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==",
+ "peerDependencies": {
+ "@redis/client": "^1.0.0"
+ }
+ },
+ "node_modules/@redis/json": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz",
+ "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==",
+ "peerDependencies": {
+ "@redis/client": "^1.0.0"
+ }
+ },
+ "node_modules/@redis/search": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz",
+ "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==",
+ "peerDependencies": {
+ "@redis/client": "^1.0.0"
+ }
+ },
+ "node_modules/@redis/time-series": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz",
+ "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==",
+ "peerDependencies": {
+ "@redis/client": "^1.0.0"
}
},
"node_modules/accepts": {
@@ -27,6 +121,20 @@
"node": ">= 0.6"
}
},
+ "node_modules/amqplib": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz",
+ "integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==",
+ "dependencies": {
+ "@acuminous/bitsyntax": "^0.1.2",
+ "buffer-more-ints": "~1.0.0",
+ "readable-stream": "1.x >=1.1.9",
+ "url-parse": "~1.5.10"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -60,6 +168,11 @@
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
},
+ "node_modules/buffer-more-ints": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
+ "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
+ },
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -80,6 +193,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/cluster-key-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
+ "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -112,6 +233,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
@@ -299,6 +425,14 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
+ "node_modules/generic-pool": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
+ "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
@@ -373,6 +507,11 @@
"node": ">= 0.10"
}
},
+ "node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
+ },
"node_modules/jsonwebtoken": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
@@ -558,6 +697,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
+ },
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -580,6 +724,35 @@
"node": ">= 0.8"
}
},
+ "node_modules/readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "node_modules/redis": {
+ "version": "4.6.6",
+ "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz",
+ "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==",
+ "dependencies": {
+ "@redis/bloom": "1.2.0",
+ "@redis/client": "1.5.7",
+ "@redis/graph": "1.1.0",
+ "@redis/json": "1.0.4",
+ "@redis/search": "1.1.2",
+ "@redis/time-series": "1.0.4"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -686,6 +859,11 @@
"node": ">= 0.8"
}
},
+ "node_modules/string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
+ },
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -714,6 +892,15 @@
"node": ">= 0.8"
}
},
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -737,6 +924,76 @@
}
},
"dependencies": {
+ "@acuminous/bitsyntax": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz",
+ "integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==",
+ "requires": {
+ "buffer-more-ints": "~1.0.0",
+ "debug": "^4.3.4",
+ "safe-buffer": "~5.1.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ }
+ }
+ },
+ "@redis/bloom": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
+ "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
+ "requires": {}
+ },
+ "@redis/client": {
+ "version": "1.5.7",
+ "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz",
+ "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==",
+ "requires": {
+ "cluster-key-slot": "1.1.2",
+ "generic-pool": "3.9.0",
+ "yallist": "4.0.0"
+ }
+ },
+ "@redis/graph": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz",
+ "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==",
+ "requires": {}
+ },
+ "@redis/json": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz",
+ "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==",
+ "requires": {}
+ },
+ "@redis/search": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz",
+ "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==",
+ "requires": {}
+ },
+ "@redis/time-series": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz",
+ "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==",
+ "requires": {}
+ },
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -746,6 +1003,17 @@
"negotiator": "0.6.3"
}
},
+ "amqplib": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz",
+ "integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==",
+ "requires": {
+ "@acuminous/bitsyntax": "^0.1.2",
+ "buffer-more-ints": "~1.0.0",
+ "readable-stream": "1.x >=1.1.9",
+ "url-parse": "~1.5.10"
+ }
+ },
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -775,6 +1043,11 @@
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
},
+ "buffer-more-ints": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
+ "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
+ },
"bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -789,6 +1062,11 @@
"get-intrinsic": "^1.0.2"
}
},
+ "cluster-key-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
+ "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="
+ },
"content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -812,6 +1090,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
"cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
@@ -966,6 +1249,11 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
+ "generic-pool": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
+ "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g=="
+ },
"get-intrinsic": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
@@ -1019,6 +1307,11 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
+ },
"jsonwebtoken": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
@@ -1157,6 +1450,11 @@
"side-channel": "^1.0.4"
}
},
+ "querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
+ },
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -1173,6 +1471,35 @@
"unpipe": "1.0.0"
}
},
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "redis": {
+ "version": "4.6.6",
+ "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz",
+ "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==",
+ "requires": {
+ "@redis/bloom": "1.2.0",
+ "@redis/client": "1.5.7",
+ "@redis/graph": "1.1.0",
+ "@redis/json": "1.0.4",
+ "@redis/search": "1.1.2",
+ "@redis/time-series": "1.0.4"
+ }
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
+ },
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -1249,6 +1576,11 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
},
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
+ },
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -1268,6 +1600,15 @@
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
},
+ "url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "requires": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
diff --git a/server/package.json b/server/package.json
index 6c77591..ecf1aaf 100644
--- a/server/package.json
+++ b/server/package.json
@@ -9,9 +9,11 @@
"author": "",
"license": "ISC",
"dependencies": {
+ "amqplib": "^0.10.3",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.18.2",
- "jsonwebtoken": "^9.0.0"
+ "jsonwebtoken": "^9.0.0",
+ "redis": "^4.6.6"
}
}
diff --git a/workers/Config/__init__.py b/workers/Config/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/workers/Config/rabbitmq.py b/workers/Config/rabbitmq.py
new file mode 100644
index 0000000..0956ed3
--- /dev/null
+++ b/workers/Config/rabbitmq.py
@@ -0,0 +1,65 @@
+from json import JSONDecodeError
+
+import pika
+from .redis import set
+import json
+
+
+class RabbitMQ:
+ connection = None
+
+ def __init__(self, queue, callback, host='localhost', durable=True):
+ self.queue = queue
+ self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=host))
+ self.channel = self.connection.channel()
+ self.channel.queue_declare(queue=self.queue, durable=durable)
+ self.callback = callback
+
+ if self.connection is None:
+ print("Connection not established")
+
+ def __del__(self):
+ if self.connection is not None:
+ self.connection.close()
+
+ def _callback(self, ch, method, properties, body):
+ if body is None:
+ return
+ try:
+ res = self.callback(body)
+ if res:
+ print(res)
+ self.ack(method)
+ except JSONDecodeError:
+ print("JSONDecodeError")
+ set('submission:' + str(body['user_id']) + ':' + str(body['problem_id']), json.dumps({"status": "Failed", "message": "Internal Error"}))
+
+ except Exception as e:
+ print(e)
+ body = json.loads(body)
+ print(body)
+ set('submission:' + str(body['user_id']) + ':' + str(body['problem_id']), json.dumps({"status": "Failed", "message": "Internal Error"}))
+ self.ack(method)
+
+ def send(self, message):
+ self.channel.basic_publish(exchange='', routing_key=self.queue, body=message)
+ print(" [x] Sent %r" % message)
+
+ def consume(self):
+ self.channel.basic_consume(queue=self.queue, on_message_callback=self._callback)
+ print(' [*] Waiting for messages. To exit press CTRL+C')
+ self.channel.start_consuming()
+
+ def receive_once(self):
+ method_frame, header_frame, body = self.channel.basic_get(queue=self.queue, auto_ack=True)
+ if method_frame:
+ print(method_frame, header_frame, body)
+ self.channel.basic_ack(method_frame.delivery_tag)
+ else:
+ print('No message returned')
+
+ def ack(self, method_frame):
+ self.channel.basic_ack(delivery_tag=method_frame.delivery_tag)
+
+ def close(self):
+ self.connection.close()
diff --git a/workers/Config/redis.py b/workers/Config/redis.py
new file mode 100644
index 0000000..459ed2d
--- /dev/null
+++ b/workers/Config/redis.py
@@ -0,0 +1,35 @@
+import redis
+import os
+
+REDIS_HOST = os.getenv('REDIS_HOST', 'localhost')
+REDIS_PORT = os.getenv('REDIS_PORT', 6379)
+REDIS_DB = os.getenv('REDIS_DB', 0)
+REDIS_PASSWORD = os.getenv('REDIS_PASSWORD', None)
+
+r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, password=REDIS_PASSWORD, decode_responses=True)
+if not r.ping():
+ raise Exception("Redis is not running")
+
+
+def get(key):
+ return r.get(key)
+
+
+def set(key, value):
+ return r.set(key, value)
+
+
+def delete(key):
+ return r.delete(key)
+
+
+def exists(key):
+ return r.exists(key)
+
+
+def keys(pattern):
+ return r.keys(pattern)
+
+
+def flushdb():
+ return r.flushdb()
diff --git a/workers/Dockerfile b/workers/Dockerfile
new file mode 100644
index 0000000..abb64ba
--- /dev/null
+++ b/workers/Dockerfile
@@ -0,0 +1,26 @@
+FROM ubuntu:latest
+
+WORKDIR /app
+
+RUN apt-get update && apt-get install -y \
+ python3 \
+ python3-pip
+
+RUN pip3 install --upgrade pip
+
+COPY requirements.txt /app/requirements.txt
+
+RUN pip3 install -r requirements.txt
+
+RUN apt-get install -y openjdk-18-jdk sudo
+
+COPY . /app
+
+RUN chmod 700 /
+
+RUN mkdir -p temp
+RUN chmod 755 -R /app/temp
+RUN adduser --disabled-password --gecos '' peetcode
+
+
+CMD ["python3", "worker.py"]
diff --git a/workers/Readme.md b/workers/Readme.md
new file mode 100644
index 0000000..1a119a5
--- /dev/null
+++ b/workers/Readme.md
@@ -0,0 +1,39 @@
+ # Code Execution service
+
+## Architecture
+
+
+## Description
+
+This implementation is very crude and done for the sake of learning.
+C, C++, Java and python are supported
+Requires to strictly follow queue schema which is
+
+```json
+{
+ "lang": "java",
+ "code": "import java.util.Scanner; public class Main {\n public static void main(String[] args) {\n int a,b; Scanner sc = new Scanner(System.in); a = sc.nextInt(); b = sc.nextInt(); System.out.println(a+b); }\n}",
+ "input": "1 2",
+ "expected_output": "3",
+ "problem_id": 1,
+ "user_id": 1
+}
+```
+
+A test Implementation can be found in `testProducer.py`
+
+I have not integrated this with the main project i.e. server and client due to my inexperienced with js, although I believe it should be easy to do so.
+
+## How to run
+
+```bash
+docker-compose up --build
+```
+
+# How to access saved data
+
+all workers use userid and problemid passed in data to save in redis
+
+default key format is: `submission:
:` which can be accessed using redis library in any language
+
+
diff --git a/workers/RunCode/__init__.py b/workers/RunCode/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/workers/RunCode/fs.py b/workers/RunCode/fs.py
new file mode 100644
index 0000000..fde7b5d
--- /dev/null
+++ b/workers/RunCode/fs.py
@@ -0,0 +1,11 @@
+import os
+
+TEMP_DIR_PATH = os.getenv('TEMP_DIR_PATH', 'temp')
+
+
+def init():
+ os.makedirs(TEMP_DIR_PATH, exist_ok=True)
+
+
+def cleanup():
+ os.system('rm -rf ' + TEMP_DIR_PATH + '/*')
diff --git a/workers/RunCode/run.py b/workers/RunCode/run.py
new file mode 100644
index 0000000..20420a2
--- /dev/null
+++ b/workers/RunCode/run.py
@@ -0,0 +1,125 @@
+import os
+import subprocess
+import resource
+import time
+
+USER = "sudo -u peetcode"
+
+ERROR_CODES = {
+ '200': 'Success',
+ 'compile_error': 'Compile Error',
+ 'runtime_error': 'Runtime Error',
+ 'time_limit_exceeded': 'Time Limit Exceeded',
+ 'memory_limit_exceeded': 'Memory Limit Exceeded',
+ 'output_limit_exceeded': 'Output Limit Exceeded',
+ 'wrong_answer': 'Wrong Answer',
+ 'unknown_error': 'Unknown Error',
+ 'language_not_supported': 'Language Not Supported',
+}
+
+LANG_EXT_MAP = {
+ 'python': 'py',
+ 'c': 'c',
+ 'cpp': 'cpp',
+ 'java': 'java',
+ 'javascript': 'js',
+}
+
+LANG_COMPILE_MAP = {
+ 'python': '200',
+ 'c': 'gcc',
+ 'cpp': 'g++',
+ 'java': 'javac',
+ 'javascript': '200',
+}
+
+LANG_RUN_MAP = {
+ 'python': 'python3',
+ 'c': './a.out',
+ 'cpp': './a.out',
+ 'java': 'java',
+ 'javascript': 'node',
+}
+
+cwd = os.environ.get('TEMP_DIR_PATH', 'temp')
+
+
+def compile(lang, filename):
+ if lang == 'python' or lang == 'javascript':
+ return {
+ "status": "200",
+ "message": "Success"
+ }
+
+ command = LANG_COMPILE_MAP[lang] + ' ' + filename
+ command = USER + ' ' + command
+
+ stdout = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
+ if stdout.returncode != 0:
+ return {
+ "status": "compile_error",
+ "message": stdout.stderr.decode('utf-8')
+ }
+
+ return {
+ "status": "200",
+ "message": stdout.stdout.decode('utf-8')
+ }
+
+
+def run_with_timeout(command, input, time_limit):
+ process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE, cwd=cwd)
+ start_time = time.time()
+ while process.poll() is None:
+ if time.time() - start_time > time_limit:
+ process.kill()
+ raise subprocess.TimeoutExpired(command, time_limit)
+
+ stdout, stderr = process.communicate(input=input.encode('utf-8'))
+
+ if process.returncode != 0:
+ error = stderr.decode('utf-8')
+ if "Killed" in error:
+ return {
+ "status": "memory_limit_exceeded",
+ "message": "Memory Limit Exceeded"
+ }
+ if "Resource temporarily unavailable" in error:
+ return {
+ "status": "output_limit_exceeded",
+ "message": "No Fork Bombs >:("
+ }
+ return {
+ "status": "runtime_error",
+ "message": stderr.decode('utf-8')
+ }
+
+ return {
+ "status": "200",
+ "message": stdout.decode('utf-8')
+ }
+
+
+def run(lang, filename, input, time_limit):
+ command = LANG_RUN_MAP[lang] + ' ' + filename
+ command = USER + ' ' + command
+ input = input if input is not None else ''
+
+ try:
+ stdout = run_with_timeout(command, input, time_limit)
+ except subprocess.TimeoutExpired:
+ return {
+ "status": "time_limit_exceeded",
+ "message": "Time Limit Exceeded"
+ }
+
+ return stdout
+
+
+def match_output(output, expected_output):
+ output = output.strip()
+ expected_output = expected_output.strip()
+ if output == expected_output:
+ return True
+ return False
diff --git a/workers/img.png b/workers/img.png
new file mode 100644
index 0000000..35cc7db
Binary files /dev/null and b/workers/img.png differ
diff --git a/workers/requirements.txt b/workers/requirements.txt
new file mode 100644
index 0000000..0b803f0
--- /dev/null
+++ b/workers/requirements.txt
@@ -0,0 +1,5 @@
+pika==1.3.2
+pip==22.3.1
+setuptools==65.5.1
+wheel==0.38.4
+redis
\ No newline at end of file
diff --git a/workers/testProducer.py b/workers/testProducer.py
new file mode 100644
index 0000000..f91be01
--- /dev/null
+++ b/workers/testProducer.py
@@ -0,0 +1,16 @@
+import pika
+import json
+connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
+channel = connection.channel()
+# channel.queue_declare(queue='code_submission_queue')
+message = {
+ "lang": "java",
+ "code": "import java.util.Scanner; public class Main {\n public static void main(String[] args) {\n int a,b; Scanner sc = new Scanner(System.in); a = sc.nextInt(); b = sc.nextInt(); System.out.println(a+b); }\n}",
+ "input": "1 2",
+ "expected_output": "3",
+ "problem_id": 1,
+ "user_id": 1
+}
+channel.basic_publish(exchange='', routing_key='code_submission', body=json.dumps(message))
+connection.close()
+print(" [x] Sent 'Hello World!'")
\ No newline at end of file
diff --git a/workers/worker.py b/workers/worker.py
new file mode 100644
index 0000000..0061551
--- /dev/null
+++ b/workers/worker.py
@@ -0,0 +1,77 @@
+from Config.rabbitmq import RabbitMQ
+from Config.redis import get, set, delete, exists, keys
+from RunCode.run import compile, run, match_output, LANG_EXT_MAP
+from RunCode.fs import init, cleanup, TEMP_DIR_PATH
+
+import json
+import os
+
+TIMEOUT = 2 # seconds
+
+def callback(body):
+ body = json.loads(body)
+ required_fields = ['lang', 'code', 'problem_id', 'user_id']
+ for field in required_fields:
+ if field not in body:
+ return {
+ "status": "400",
+ "message": "Bad Request"
+ }
+
+ cleanup()
+ print(body)
+ lang = body['lang']
+ code = body['code']
+ input = body['input'] if 'input' in body else None
+ expected_output = body['expected_output'] if 'expected_output' in body else None
+ problem_id = body['problem_id']
+ user_id = body['user_id']
+ set('submission:' + str(user_id) + ':' + str(problem_id), json.dumps({"status": "running", "message": "Running"}))
+
+ filename = 'Main.' + LANG_EXT_MAP[lang]
+ with open(TEMP_DIR_PATH + '/' + filename, 'w') as f:
+ f.write(code)
+
+ compile_status = compile(lang, filename)
+ if compile_status['status'] != '200':
+ set('submission:' + str(user_id) + ':' + str(problem_id), json.dumps(compile_status))
+ return compile_status
+
+ run_status = run(lang, filename, input, TIMEOUT)
+ if run_status['status'] != '200':
+ set('submission:' + str(user_id) + ':' + str(problem_id), json.dumps(run_status))
+ return run_status
+
+ if expected_output is not None:
+ if not match_output(run_status['message'], expected_output):
+ status = {
+ "status": "wrong_answer",
+ "message": "Wrong Answer"
+ }
+
+ set('submission:' + str(user_id) + ':' + str(problem_id), json.dumps(status))
+ return status
+
+ status = {
+ "status": "correct_answer",
+ "message": "Correct Answer"
+ }
+ set('submission:' + str(user_id) + ':' + str(problem_id), json.dumps(status))
+ return status
+
+
+def main():
+ init()
+ host = os.environ.get('RABBITMQ_HOST', 'localhost')
+ print(host)
+ rabbitmq = RabbitMQ("code_submission", callback, host=host)
+ try:
+ rabbitmq.consume()
+ cleanup()
+ except KeyboardInterrupt:
+ cleanup()
+ rabbitmq.close()
+
+
+if __name__ == '__main__':
+ main()