Spaces:
Running
Running
/** | |
* 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 = `<div id="logContainer"></div>`; | |
const COMMON_STYLES = ` | |
<style> | |
#logContainer { | |
height: 400px; | |
overflow-y: scroll; | |
background-color: black; | |
color: lime; | |
font-family: 'Courier New', Courier, monospace; | |
padding: 10px; | |
white-space: pre-wrap; | |
border: 1px solid #ddd; | |
} | |
.highlight-button { | |
animation: pulseAnimation 1s infinite; | |
background-color: yellow; | |
color: black; | |
font-weight: bold; | |
} | |
@keyframes pulseAnimation { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.1); } | |
100% { transform: scale(1); } | |
} | |
</style>`; | |
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 ` | |
<html> | |
<head> | |
<title>Proxy Server</title> | |
${COMMON_STYLES} | |
</head> | |
<body> | |
${buttonsHTML} | |
${LOG_CONTAINER_HTML} | |
<script> | |
function startServer() { | |
document.getElementById('startServerButton').classList.remove | |
('highlight-button'); | |
document.getElementById('startServerButton').disabled = true; | |
fetch('/start-omnitool-server') | |
.then(response => response.json()) | |
.then(data => startLogPolling()); | |
} | |
function exitIframe() { | |
fetch('/burst-iframe') | |
.then(response => response.json()) | |
.then(data => window.open('/', '_blank')); | |
} | |
function startLogPolling() { | |
const interval = setInterval(() => { | |
fetch('/omnitool-logs') | |
.then(response => response.json()) | |
.then(data => { | |
const logContainer = document.getElementById('logContainer'); | |
logContainer.innerText = data.logs.join("\\n"); | |
if (data.ready) { | |
clearInterval(interval); | |
} | |
else { | |
scrollToBottom(logContainer); | |
} | |
}); | |
}, 500); | |
} | |
function scrollToBottom(element) { | |
element.scrollTop = element.scrollHeight; | |
} | |
startLogPolling(); | |
</script> | |
</body> | |
</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 = `<button id="startServerButton" class="${startButtonClass}" onclick="startServer()">Start Omnitool Server</button>`; | |
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 = `<button id="exitIframeButton" class="${gotoButtonClass}" onclick="exitIframe()">GOTO OMNITOOL</button>`; | |
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); | |