/** * Copyright (c) 2023 MERCENARIES.AI PTE. LTD. * All rights reserved. */ //@ts-check const express = require('express'); const http = require('http'); const session = require('express-session'); const axios = require('axios'); const { spawn } = require('child_process'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express(); const CONTAINER_HOST = '127.0.0.1'; const PROXY_PORT_OMNITOOL = 4444; const CONTAINER_PORT_OMNITOOL = 1688; const DELAY_OMNITOOL_SET_TO_RUNNING = 2000; // 2 seconds const CHECK_OMNI_INTERVAL = 60000; // 1 minute // Global variable global.OMNITOOL_RUNNING = false; global.OMNITOOL_READY = false; global.ALREADY_STARTING = false; global.LOCAL_URL = ""; global.PING_URL = ""; global.PROTOCOL = ""; const VERSION = '0.0.8a'; console.log(`************ Omnitool Proxy Server v${VERSION} ************`); let omnitoolLogs = []; // HTML templates and constants const LOG_CONTAINER_HTML = `
`; const COMMON_STYLES = ` `; async function startOmnitoolServer() { if (global.ALREADY_STARTING) return; global.ALREADY_STARTING = true; console.log('Starting Omnitool Server...'); return new Promise((resolve, reject) => { const omnitoolStartProcess = spawn('./omnitool_start.sh'); omnitoolStartProcess.stdout.on('data', (data) => { omnitoolLogs.push(data.toString()); console.log(`omnitool stdout: ${data}`); }); omnitoolStartProcess.stderr.on('data', (data) => { console.error(`omnitool stderr: ${data}`); omnitoolLogs.push(data.toString()); }); omnitoolStartProcess.on('close', (code) => { const message = `Omnitool server process exited with code: ${code}`; console.log(message); omnitoolLogs.push(message); global.ALREADY_STARTING = false; if (code === 0) { //@ts-ignore resolve(); } else { reject(`Omnitool server did not start properly.`); } }); }); } function setOmnitoolRunning(set_running) { if (set_running === true) { if (global.OMNITOOL_READY === false) { global.OMNITOOL_READY = true; console.log('Omnitool server is READY! '); setTimeout(() => { console.log('Omnitool server is RUNNING! '); global.OMNITOOL_RUNNING = true; }, DELAY_OMNITOOL_SET_TO_RUNNING); // Delay by 2 second } } else { global.OMNITOOL_READY = false; global.OMNITOOL_RUNNING = false; } } // Function to check the status of the external service async function checkOmnitoolStatus() { console.log("Checking external service"); try { //@ts-ignore const response = await axios.get('http://127.0.0.1:1688/api/v1/mercenaries/ping'); if (response.data && response.data.ping === 'pong' && Object.keys(response.data.payload).length === 0) { setOmnitoolRunning(true); } else { setOmnitoolRunning(false); } } catch (error) { console.error('Cannot access OMNITOOL. It is probably not running...', error.message); setOmnitoolRunning(false); } } async function handleGetStartOmnitoolServer(req, res) { console.log(`Omnitool Server:ALREADY_STARTING = ${global.ALREADY_STARTING}`); if (global.ALREADY_STARTING) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end("Omnitool server already starting"); return; } try { await startOmnitoolServer(); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end("Omnitool server started successfully"); } catch (error) { console.error(error); global.ALREADY_STARTING = false; res.writeHead(500, { 'Content-Type': 'text/html' }); res.end(`Error starting Omnitool server: ${error}`); } } async function handleGetOmnitoolLogs(req, res) { res.writeHead(200, { 'Content-Type': 'application/json' }); const reply = { logs: omnitoolLogs, ready:global.OMNITOOL_READY }; res.end(JSON.stringify(reply)); return; } async function handleGetBurstIframe(req, res) { res.writeHead(200, { 'Content-Type': 'application/json' }); req.session.isVisited = true; const reply = { burst_iframe: true }; res.end(JSON.stringify(reply)); return; } async function proxyRequest(req, res) { // Proxy logic... const options = { hostname: CONTAINER_HOST, port: CONTAINER_PORT_OMNITOOL, path: req.url, method: req.method, headers: req.headers, }; const proxy = http.request(options, (proxyRes) => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res, { end: true }); }); req.pipe(proxy, { end: true }); return; } function getButtonsString(buttonsHTML, gotoUrl) { return ` Proxy Server ${COMMON_STYLES} ${buttonsHTML} ${LOG_CONTAINER_HTML} `; } async function handleGetRoot(req, res) { if (global.LOCAL_URL === "") setGlobals(req); console.log(`req.session.isVisited = ${req.session.isVisited}`); console.log(`global.OMNITOOL_RUNNING = ${global.OMNITOOL_RUNNING}`); if (!req.session.isVisited) { await checkOmnitoolStatus(); } if (!global.OMNITOOL_RUNNING) { let startButtonClass = 'highlight-button'; let buttonsHTML = ``; const html = getButtonsString(buttonsHTML, global.LOCAL_URL); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(html); return; } if (!req.session.isVisited) { console.log(`-----> global.LOCAL_URL = ${global.LOCAL_URL}`); const gotoButtonClass = 'highlight-button'; const buttonsHTML = ``; const html = getButtonsString(buttonsHTML, global.LOCAL_URL); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(html); return; } proxyRequest(req, res); } function setGlobals(req) { global.LOCAL_URL = req.headers['host']; if (req.protocol === "https") global.PROTOCOL = 'https'; else global.PROTOCOL = 'http'; if (!global.LOCAL_URL) throw new Error('No host header found in request' + JSON.stringify(req.headers, null, 2)); const hostname = global.LOCAL_URL.split(':')[0]; const newUrl = `${global.PROTOCOL}://${hostname}`;//:${PROXY_PORT_OMNITOOL}`; global.PING_URL = `${newUrl}/api/v1/mercenaries/ping`; } async function startServer() { // Start server const PORT = 4444; http.createServer(app).listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); } const OMNI_URL = 'http://127.0.0.1:1688'; // URL of the OMNITOOL service function omnitoolProxyMiddleware(req, res, next) { if (global.OMNITOOL_RUNNING && req.session.isVisited) { // Proxy all requests to OMNITOOL when conditions are met return createProxyMiddleware({ target: OMNI_URL, changeOrigin: true, ws: true // if you need WebSocket support })(req, res, next); } else { // Continue with normal processing for other cases next(); } } async function main(app) { checkOmnitoolStatus(); // Configure session middleware app.use(session({ secret: 'your-secret-key', resave: false, saveUninitialized: true })); await startServer(); app.use(omnitoolProxyMiddleware); app.get('/favicon.ico', (req, res) => res.status(204)); app.get('/start-omnitool-server', (req, res) => handleGetStartOmnitoolServer(req, res)); app.get('/omnitool-logs', (req, res) => handleGetOmnitoolLogs(req, res)); app.get('/burst-iframe', (req, res) => handleGetBurstIframe(req, res)); app.get('/', (req, res) => handleGetRoot(req, res)); setInterval(async () => { await checkOmnitoolStatus(); }, CHECK_OMNI_INTERVAL); //const server = http.createServer(async (req, res) => handleRoutes(req, res, app)); //server.listen(PROXY_PORT_OMNITOOL, '0.0.0.0'); console.log(`Server running on port ${PROXY_PORT_OMNITOOL}`); } main(app);