sanket3280/code-execution
0
1const axios = require('axios');2const Language = require('../models/Language');3 4// Note: HackerEarth supported languages endpoint reference placeholder.5// If an official endpoint is available, configure it via env. Else, maintain a curated map6const HE_LANG_ENDPOINT = process.env.HE_LANG_ENDPOINT || '';7 8// Fallback curated list to seed when endpoint is not available9const CURATED_LANGUAGES = [10 { heCode: 'JAVASCRIPT_NODE', displayName: 'JavaScript', version: 'Node', iconName: 'javascript' },11 { heCode: 'PYTHON3', displayName: 'Python', version: '3', iconName: 'python' },12 { heCode: 'JAVA17', displayName: 'Java', version: '17', iconName: 'java' },13 { heCode: 'CPP14', displayName: 'C++', version: '14', iconName: 'cpp' },14 { heCode: 'C', displayName: 'C', version: '', iconName: 'c' },15 { heCode: 'CSHARP', displayName: 'C#', version: '', iconName: 'csharp' },16];17 18async function fetchLanguagesFromHE() {19 if (!HE_LANG_ENDPOINT) return CURATED_LANGUAGES;20 try {21 const headers = {};22 if (process.env.CLIENT_SECRET) headers['client-secret'] = process.env.CLIENT_SECRET;23 const { data } = await axios.get(HE_LANG_ENDPOINT, { headers, timeout: 10000 });24 // Expect data to be an array of { code, displayName, version }25 const list = Array.isArray(data) ? data : (data.languages || []);26 return list.map((l) => ({27 heCode: l.code || l.heCode,28 displayName: l.displayName || l.name || l.title || l.code,29 version: l.version || '',30 iconName: l.iconName || '',31 }));32 } catch (err) {33 console.error('Failed to fetch HE languages, using curated fallback:', err.message);34 return CURATED_LANGUAGES;35 }36}37 38async function upsertLanguages(languages) {39 // Parallelize language upserts40 await Promise.all(41 languages.map(async (lang) => {42 try {43 const { heCode, displayName, version, iconName } = lang;44 // Upsert by heCode first; fallback to displayName+version45 let existing = await Language.findOne({ heCode });46 if (!existing && displayName) {47 existing = await Language.findOne({ displayName, version: version || '' });48 }49 50 if (existing) {51 existing.displayName = displayName || existing.displayName;52 existing.version = version || existing.version;53 if (iconName !== undefined) existing.iconName = iconName;54 await existing.save();55 } else {56 await Language.create({ heCode, displayName, version: version || '', iconName: iconName || '' });57 }58 } catch (e) {59 console.error('Language upsert error:', e.message);60 }61 })62 );63}64 65async function syncLanguages() {66 const langs = await fetchLanguagesFromHE();67 await upsertLanguages(langs);68 return await Language.find({}).lean();69}70 71async function getAllowedLanguagesForProblem(problemDoc) {72 const hasAllowList = Array.isArray(problemDoc.allowedLanguages) && problemDoc.allowedLanguages.length > 0;73 const allLangs = await Language.find({}).lean();74 75 // Compute allowed flag76 const allowedSet = new Set(hasAllowList ? problemDoc.allowedLanguages : []);77 const langsWithAllowed = allLangs.map(l => {78 const globallyEnabled = !!l.enabled;79 const allowed = hasAllowList ? (allowedSet.has(l.heCode) && globallyEnabled) : globallyEnabled;80 return {81 heCode: l.heCode,82 displayName: l.displayName,83 version: l.version,84 iconName: l.iconName,85 allowed86 };87 });88 89 // Sorting: allowed + popular first, then others alphabetically90 const popularOrder = ['JAVASCRIPT_NODE', 'PYTHON3', 'JAVA17', 'CPP14', 'C', 'CSHARP'];91 langsWithAllowed.sort((a, b) => {92 if (a.allowed !== b.allowed) return a.allowed ? -1 : 1;93 const ai = popularOrder.indexOf(a.heCode);94 const bi = popularOrder.indexOf(b.heCode);95 if (ai !== -1 || bi !== -1) {96 if (ai === -1) return 1;97 if (bi === -1) return -1;98 return ai - bi;99 }100 const an = (a.displayName || '').toLowerCase();101 const bn = (b.displayName || '').toLowerCase();102 return an.localeCompare(bn);103 });104 105 return langsWithAllowed;106}107 108module.exports = {109 syncLanguages,110 getAllowedLanguagesForProblem,111};112 113 114 