Skip to content

Commit afde039

Browse files
committed
chore: Pull before push
1 parent 7b7007c commit afde039

26 files changed

+1081
-0
lines changed

express_backend/.prettierrc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"trailingComma": "none",
3+
"tabWidth": 4,
4+
"semi": true,
5+
"singleQuote": true,
6+
"bracketSameLine": true,
7+
"printWidth": 150,
8+
"singleAttributePerLine": true,
9+
"endOfLine": "crlf"
10+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// commitlint.config.js
2+
3+
module.exports = {
4+
extends: ['@commitlint/cli', '@commitlint/config-conventional'],
5+
rules: {
6+
'type-enum': [
7+
2, // level: error
8+
'always', // applicable condition
9+
[
10+
'feat', // New feature
11+
'fix', // Bug fix
12+
'docs', // Documentation changes
13+
'style', // Code style changes (formatting, missing semi colons, etc.)
14+
'refactor',// Code refactoring (neither fixes a bug nor adds a feature)
15+
'perf', // Performance improvements
16+
'test', // Adding missing tests or correcting existing tests
17+
'build', // Changes affecting the build system or external dependencies
18+
'ci', // Changes to CI configuration files and scripts
19+
'chore', // Other changes that don’t modify src or test files
20+
'revert' // Reverts a previous commit
21+
]
22+
],
23+
'subject-case': [
24+
2, // level: error
25+
'always', // applicable condition
26+
['sentence-case', 'start-case', 'pascal-case', 'upper-case']
27+
],
28+
},
29+
};

express_backend/ecosystem.config.js

Whitespace-only changes.

express_backend/eslint.config.mjs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// @ts-check
2+
3+
import eslint from '@eslint/js';
4+
import tseslint from 'typescript-eslint';
5+
import eslintConfigPrettier from 'eslint-config-prettier'
6+
7+
export default tseslint.config(
8+
{
9+
languageOptions: {
10+
parserOptions: {
11+
project: true,
12+
tsconfigRootDir: import.meta.dirname,
13+
},
14+
},
15+
files: ['**/*.ts'],
16+
extends: [
17+
eslint.configs.recommended,
18+
...tseslint.configs.recommended,
19+
eslintConfigPrettier
20+
],
21+
rules: {
22+
// this is done so that there is no console while we push code to github production
23+
// large number of consoles slow down the performance of the code
24+
'no-console': 'off',
25+
'no-useless-catch': 0,
26+
quotes: ['error', 'single', { allowTemplateLiterals: true }],
27+
}
28+
}
29+
);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// we don't need an output file for this becuase python is interpreted langauge
2+
const { exec } = require("child_process");
3+
const fs = require("fs");
4+
const path = require("path");
5+
6+
const outputPath = path.join(__dirname, "outputs");
7+
8+
if (!fs.existsSync(outputPath)) {
9+
fs.mkdirSync(outputPath, { recursive: true });
10+
}
11+
const executePy = (filepath, inputs) => {
12+
13+
const jobId = path.basename(filepath).split(".")[0];
14+
15+
// getting the output path where the ouput will be generated
16+
const outPath = path.join(outputPath, `${jobId}.out`);
17+
18+
// creating input file path
19+
const inputFilePath = path.join(outputPath, `${jobId}.txt`);
20+
fs.writeFileSync(inputFilePath, inputs);
21+
return new Promise((resolve, reject) => {
22+
exec(
23+
`python3 ${filepath} < ${inputFilePath}`,
24+
(error, stdout, stderr) => {
25+
fs.unlinkSync(inputFilePath);
26+
27+
if (error) {
28+
reject({ error, stderr });
29+
} else if (stderr) {
30+
reject(stderr);
31+
} else {
32+
resolve(stdout);
33+
}
34+
}
35+
);
36+
});
37+
};
38+
39+
module.exports = {
40+
executePy,
41+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const { exec } = require("child_process");
2+
const fs = require("fs");
3+
const path = require("path");
4+
5+
const outputPath = path.join(__dirname, "outputs");
6+
7+
if (!fs.existsSync(outputPath)) {
8+
fs.mkdirSync(outputPath, { recursive: true });
9+
}
10+
11+
const executeCpp = (filepath, inputs) => {
12+
// getting the file name
13+
const jobId = path.basename(filepath).split(".")[0];
14+
15+
// getting the output path where the ouput will be generated
16+
const outPath = path.join(outputPath, `${jobId}.out`);
17+
18+
// creating input file path
19+
const inputFilePath = path.join(outputPath, `${jobId}.txt`);
20+
fs.writeFileSync(inputFilePath, inputs);
21+
22+
return new Promise((resolve, reject) => {
23+
exec(
24+
`g++ ${filepath} -o ${outPath} && cd ${outputPath} && ./${jobId}.out < ${inputFilePath}`,
25+
(error, stdout, stderr) => {
26+
error && reject({ error, stderr });
27+
stderr && reject(stderr);
28+
resolve(stdout);
29+
}
30+
);
31+
});
32+
};
33+
34+
module.exports = {
35+
executeCpp,
36+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const fs = require("fs");
2+
const path = require("path");
3+
const { v4: uuid } = require("uuid");
4+
5+
const dirCodes = path.join(__dirname, "generated_codes");
6+
7+
if (!fs.existsSync(dirCodes)) {
8+
fs.mkdirSync(dirCodes, { recursive: true });
9+
}
10+
11+
const generateFile = async (format, content) => {
12+
13+
// generating random id
14+
const jobId = uuid();
15+
16+
// generating name of the file
17+
const filename = `${jobId}.${format}`;
18+
19+
// fetching file name
20+
const filepath = path.join(dirCodes, filename);
21+
22+
// write incoming on the file
23+
fs.writeFileSync(filepath, content);
24+
25+
return filepath;
26+
};
27+
28+
module.exports = {
29+
generateFile,
30+
};
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
const { Queue, Worker } = require('bullmq');
2+
const jobs = require('../models/jobs');
3+
const { executeCpp } = require('./code_execution/execute_cpp');
4+
const { executePy } = require('./code_execution/executePy');
5+
const Problem = require('../models/problem_model');
6+
7+
const getRedisClient = require('../config/get_redis_client');
8+
9+
const redisClient = getRedisClient();
10+
11+
// Create a new BullMQ queue
12+
const jobQueue = new Queue('job-queue', {
13+
connection: redisClient
14+
});
15+
16+
17+
// Create a worker to process jobs
18+
const worker = new Worker('job-queue', async job => {
19+
const jobId = job.data.id;
20+
console.log(jobId)
21+
const jobDoc = await jobs.findById(jobId);
22+
if (!jobDoc) {
23+
throw new Error(`Cannot find Job with id ${jobId}`);
24+
}
25+
const problemId = job.data.problemId;
26+
27+
const problem = await Problem.findOne({ id: problemId }).populate('testCases');
28+
29+
if (!problem) {
30+
throw Error(`Cannot find Problem with id ${problemId}`);
31+
}
32+
33+
console.log("Processing job:", job.data);
34+
35+
const mismatches = [];
36+
try {
37+
let output;
38+
jobDoc.startedAt = new Date();
39+
40+
if (jobDoc.language === "cpp") {
41+
for (const testCase of problem.testCases) {
42+
output = await executeCpp(jobDoc.filepath, testCase.input);
43+
if (output.trim() !== testCase.output.trim()) {
44+
mismatches.push({
45+
input: testCase.input,
46+
expectedOutput: testCase.output,
47+
actualOutput: output
48+
});
49+
}
50+
}
51+
} else if (jobDoc.language === "py") {
52+
output = await executePy(jobDoc.filepath);
53+
}
54+
55+
jobDoc.completedAt = new Date();
56+
jobDoc.output = output;
57+
jobDoc.status = mismatches.length ? "error" : "success";
58+
jobDoc.mismatches = mismatches;
59+
60+
await jobDoc.save();
61+
return true;
62+
} catch (err) {
63+
jobDoc.completedAt = new Date();
64+
jobDoc.output = JSON.stringify(err);
65+
jobDoc.status = "error";
66+
jobDoc.mismatches = mismatches;
67+
68+
await jobDoc.save();
69+
throw err;
70+
}
71+
}, {
72+
connection: redisClient,
73+
concurrency: 5
74+
});
75+
76+
77+
worker.on('failed', (job, err) => {
78+
console.error(`Job ${job.id} failed with error:`, err);
79+
});
80+
81+
process.on('SIGINT', async () => {
82+
console.log('Shutting down gracefully...');
83+
await worker.close();
84+
await redisClient.quit();
85+
process.exit(0);
86+
});
87+
88+
// Add jobs to the queue
89+
const addJobToQueue = async ({ jobId, problemId, language, filepath }) => {
90+
try {
91+
await jobQueue.add('job', {
92+
id: jobId,
93+
problemId: problemId,
94+
language: language,
95+
filepath: filepath
96+
});
97+
console.log(`Added job ${jobId} to the queue.`);
98+
} catch (err) {
99+
console.error(`Error adding job ${jobId} to queue:`, err);
100+
}
101+
}
102+
103+
module.exports = {
104+
addJobToQueue
105+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
const Queue = require('bull');
2+
const jobs = require('../models/jobs');
3+
const { executeCpp } = require('./code_execution/execute_cpp');
4+
const { executePy } = require('./code_execution/executePy');
5+
6+
const jobQueuePlayground = new Queue('job-queue-playground');
7+
const NUM_WORKERS = 5;
8+
9+
jobQueuePlayground.process(NUM_WORKERS, async ({ data }) => {
10+
const jobId = data.id;
11+
12+
// finding the job with id of the job
13+
const job = await jobs.findById(jobId);
14+
15+
// if job not found, throw error
16+
if (job === undefined) {
17+
throw Error(`cannot find Job with id ${jobId}`);
18+
}
19+
20+
21+
try {
22+
23+
let output;
24+
25+
// writing started at time
26+
job["startedAt"] = new Date();
27+
28+
//
29+
if (job.language === "cpp") {
30+
31+
// executing code for C++
32+
output = await executeCpp(job.filepath, data.inputs);
33+
34+
} else if (job.language === "py") {
35+
36+
// executing code for python
37+
output = await executePy(job.filepath, data.inputs);
38+
}
39+
40+
job["completedAt"] = new Date();
41+
42+
// setting up the output generated by the code
43+
job["output"] = output;
44+
45+
// output generated -> success, job executed successfully
46+
// doesn't matter if code contains error
47+
// it just shows, wheather code entered executed correctly
48+
// or not
49+
job["status"] = "success";
50+
51+
// saving the job
52+
await job.save();
53+
54+
return true;
55+
56+
} catch (err) {
57+
job["completedAt"] = new Date();
58+
job["output"] = JSON.stringify(err);
59+
job["status"] = "error";
60+
await job.save();
61+
throw Error(JSON.stringify(err));
62+
}
63+
})
64+
65+
jobQueuePlayground.on("failed", (error) => {
66+
console.error(error.data.id, error.failedReason);
67+
});
68+
69+
const addJobToQueueForPlayground = async ({ jobId, inputs, language, filepath }) => {
70+
await jobQueuePlayground.add({
71+
id: jobId,
72+
inputs: inputs,
73+
language: language,
74+
filepath: filepath
75+
});
76+
}
77+
78+
module.exports = {
79+
addJobToQueueForPlayground
80+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const mongoose = require("mongoose");
2+
require("dotenv").config();
3+
4+
const { MONGODB_URL } = process.env;
5+
6+
exports.connect = () => {
7+
mongoose
8+
.connect(MONGODB_URL, {
9+
useNewUrlparser: true,
10+
useUnifiedTopology: true,
11+
})
12+
.then(console.log(`DB Connection Success`))
13+
.catch((err) => {
14+
console.log(`DB Connection Failed`);
15+
console.log(err);
16+
process.exit(1);
17+
});
18+
};

0 commit comments

Comments
 (0)