const express = require('express'); const router = express.Router(); const readline = require('readline'); const fs = require('fs'); const rcon = require("../modules/rcon"); const is_authenticated = require("../modules/middleware"); const ALLOWED_STEAM_IDS = ['76561198154367261'] router.post('/api/setup-game', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const team1 = req.body.team1; const team2 = req.body.team2; const selected_map = req.body.selectedMap; const game_mode = req.body.game_mode.toString(); rcon.rcons[server_id].execute(`mp_teamname_1 "${team1}"`); rcon.rcons[server_id].execute(`mp_teamname_2 "${team2}"`); rcon.rcons[server_id].execute(`game_mode ${game_mode}`); if (game_mode == "1") { execute_cfg_on_server(server_id, './cfg/live.cfg'); } else if (game_mode == "2") { execute_cfg_on_server(server_id, './cfg/live_wingman.cfg'); } rcon.rcons[server_id].execute(`mp_warmup_pausetimer 1`); rcon.rcons[server_id].execute(`changelevel ${selected_map}`); // Adding 1 second delay in executing warmup.cfg to make it effective after map has been changed. setTimeout(() => { execute_cfg_on_server(server_id, './cfg/warmup.cfg'); }, 1000) return res.status(200).json({ message: 'Game Created!' }); } catch (error) { console.log(error); res.status(500).json({ error: 'Internal server error' }); } }); router.post('/api/restart', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; rcon.rcons[server_id].execute('mp_restartgame 1'); return res.status(200).json({ message: 'Game restarted' }); } catch (error) { console.log(error); res.status(500).json({ error: 'Internal server error' }); } }); router.post('/api/start-warmup', is_authenticated, (req, res) => { try { const server_id = req.body.server_id; rcon.rcons[server_id].execute('mp_restartgame 1'); execute_cfg_on_server(server_id, './cfg/warmup.cfg'); return res.status(200).json({ message: 'Warmup started!' }); } catch (error) { console.log(error); res.status(500).json({ error: 'Internal server error' }); } }); router.post('/api/start-knife', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; rcon.rcons[server_id].execute('mp_warmup_end'); rcon.rcons[server_id].execute('mp_restartgame 1'); execute_cfg_on_server(server_id, './cfg/knife.cfg'); return res.status(200).json({ message: 'Knife started!' }); } catch (error) { console.log(error); res.status(500).json({ error: 'Internal server error' }); } }); router.post('/api/swap-team', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; rcon.rcons[server_id].execute('mp_swapteams'); return res.status(200).json({ message: 'Teams Swapped!' }); } catch (error) { res.status(500).json({ error: 'Internal server error' }); } }); router.post('/api/go-live', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; rcon.rcons[server_id].execute('mp_warmup_end'); const response = await rcon.rcons[server_id].execute('game_mode'); const game_mode = response.split("=")[1].trim().toString(); if (game_mode == "1") { console.log("Executing live.cfg") execute_cfg_on_server(server_id, './cfg/live.cfg'); } else if (game_mode == "2") { console.log("Executing live_wingman.cfg") execute_cfg_on_server(server_id, './cfg/live_wingman.cfg'); } rcon.rcons[server_id].execute('mp_restartgame 1'); return res.status(200).json({ message: 'Match is live!!' }); } catch (error) { console.log(error); res.status(500).json({ error: 'Internal server error' }); } }); // List Round Backups API router.post('/api/list-backups', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const response = await rcon.rcons[server_id].execute('mp_backup_restore_list_files'); console.log('Server response:', response); return res.status(200).json({ message: response }); } catch (error) { console.log(error) res.status(500).json({ error: 'Internal server error' }); } }); // Restore Round API router.post('/api/restore-round', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; let round_number = req.body.round_number.toString() if (round_number.length == 1) { round_number = "0" + round_number; } console.log(`SENDING mp_backup_restore_load_file backup_round${round_number}.txt`) rcon.rcons[server_id].execute(`mp_backup_restore_load_file backup_round${round_number}.txt`); rcon.rcons[server_id].execute('mp_pause_match'); return res.status(200).json({ message: 'Round Restored!' }); } catch (error) { res.status(500).json({ error: 'Internal server error' }); } }); router.post('/api/restore-latest-backup', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const response = await rcon.rcons[server_id].execute('mp_backup_round_file_last'); const last_round_file = response.split("=")[1].trim().toString(); if (last_round_file.includes('.txt')) { rcon.rcons[server_id].execute(`mp_backup_restore_load_file ${last_round_file}`); rcon.rcons[server_id].execute('mp_pause_match'); return res.status(200).json({ message: `Latest Round Restored! (${last_round_file})` }); } else { return res.status(200).json({ message: 'No latest backup found!' }); } } catch (error) { console.log(error); res.status(500).json({ error: 'Internal server error' }); } }); // Pause Game API router.post('/api/pause', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; rcon.rcons[server_id].execute('mp_pause_match'); return res.status(200).json({ message: 'Game paused' }); } catch (error) { res.status(500).json({ error: 'Internal server error' }); } }); // Unpause Game API router.post('/api/unpause', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; rcon.rcons[server_id].execute('mp_unpause_match'); return res.status(200).json({ message: 'Game unpaused' }); } catch (error) { res.status(500).json({ error: 'Internal server error' }); } }); router.post('/api/rcon', is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const command = req.body.command; // Wrap the await call in a Promise and add a timeout const executePromise = new Promise(async (resolve, reject) => { try { const response = await Promise.race([ rcon.rcons[server_id].execute(command), new Promise((resolve, reject) => { setTimeout(() => { resolve({ error: 'Command execution timed out' }); }, 1000); // 1 seconds timeout }), ]); resolve(response); } catch (error) { reject(error); } }); // Wait for the wrapped Promise to resolve const response = await executePromise; console.log(response) // Check if the result is an error or the actual response if (response.error) { return res.status(200).json({ message: 'Command sent!' }); } return res.status(200).json({ message: 'Command sent! Response received:\n' + response.toString() }); } catch (error) { res.status(500).json({ error: 'Internal server error' }); } }); function check_whitelisted_players() { rcon.rcons[server_id].execute('status_json') .then((response) => { console.log(response) const server_status = JSON.parse(response) const players = server_status['server']['clients'] for (var i = 0; i < players.length; i++) { let player = players[i] if (!player.bot && player.steamid64.includes('7656') && !ALLOWED_STEAM_IDS.includes(player.steamid64)) { console.log(`kick ${player.name}`) rcon.rcons[server_id].execute(`kick ${player.name}`); } } return; }) .catch(console.error); } function splitByByteLength(data, length) { const lines = data; const exportedLines = []; const lineEndChar = '; ' let index = 0; for(let item = 0; item < lines.length; item++) { if(typeof exportedLines[index] === "undefined") { exportedLines[index] = ""; } const lineFormatted = `${lines[item]}${lineEndChar}`; const lineBytes = Buffer.byteLength(lineFormatted, 'utf8'); const bufferBytes = Buffer.byteLength(exportedLines[index], 'utf8'); if((bufferBytes + lineBytes) < length) { exportedLines[index] += lineFormatted; } else { index++; } } return exportedLines; } function execute_cfg_on_server(server_id, cfg_path) { fs.readFile(cfg_path, 'utf8', (err, data) => { if (err) { throw err; } data = data.replace(/^\/\/.*$/m, ''); data = data.split("\n"); const new_data = []; for (let i = 0; i < data.length; i += 1) { const line = data[i].trim(); const segments = line.split(' '); if(segments[0] === 'say' || segments.length == 1) { new_data.push(line); } else if (segments[0] !== '' && segments[0] !== '//') { new_data.push(`${segments[0]} ${segments[1].split('\t')[0]}`); } } const exported_lines = splitByByteLength(data, 512) function execute_next_item(item) { try { if (item < exported_lines.length) { console.log(exported_lines[item]); rcon.rcons[server_id].execute(exported_lines[item]); // Wait for 200ms before moving to the next iteration setTimeout(() => { execute_next_item(item + 1); }, 200); } } catch (error) { console.log("[execute_next_item] Error:", error) } } execute_next_item(0); }); } module.exports = { router };