playwright / app.js
RynnHub's picture
hmm
d8f7b5b
const express = require('express');
const { chromium } = require('playwright');
const cors = require('cors');
const dotenv = require('dotenv');
const { NodeVM } = require('vm2');
const os = require('os');
const axios = require('axios');
const fetch = require('node-fetch');
dotenv.config();
const app = express();
app.set('json spaces', 2);
app.use(express.json());
app.use(cors());
app.get('/', (req, res) => {
const formatMemory = (bytes) => {
const gb = bytes / 1024 / 1024 / 1024;
if (gb >= 1) {
return gb.toFixed(2) + ' GB';
} else {
return (bytes / 1024 / 1024).toFixed(2) + ' MB';
}
};
const cpuModel = os.cpus().length > 0
? os.cpus()[0].model.replace(/\s+/g, ' ').trim()
: 'Unknown';
const uptime = (() => {
const totalSeconds = os.uptime();
const days = Math.floor(totalSeconds / (3600 * 24));
const hours = Math.floor((totalSeconds % (3600 * 24)) / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
return `${days}d ${hours}h ${minutes}m`;
})();
const memoryUsedPercentage = ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(2);
res.json({
status: "online",
uptime: uptime,
cpu: {
model: cpuModel,
cores: os.cpus().length,
load: os.loadavg()[0].toFixed(2) + '%'
},
memory: {
total: formatMemory(os.totalmem()),
used: formatMemory(os.totalmem() - os.freemem()) + ` (${memoryUsedPercentage}%)`,
free: formatMemory(os.freemem())
},
info_api: [
{
path: '/run',
method: 'POST',
description: 'Run Playwright code in a sandboxed VM environment',
body: {
code: 'JavaScript code to execute (required)',
timeout: 'Execution timeout in milliseconds (optional, default: 300000)'
}
}
]
});
});
app.post('/run', async (req, res) => {
const { code, timeout = 300000 } = req.body;
if (!code) return res.status(400).json({ error: 'Code cannot be empty' });
let output = [];
const originalLog = console.log;
console.log = (...args) => {
const message = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg) : arg)).join(' ');
output.push(message);
originalLog.apply(console, args);
};
const vm = new NodeVM({
console: 'inherit',
sandbox: {},
require: {
external: true,
builtin: ['fs', 'path'],
root: './',
mock: {
playwright: { chromium },
axios,
'node-fetch': fetch,
},
},
});
const script = `
module.exports = async () => {
${code}
};
`;
let runCode;
try {
runCode = vm.run(script, 'sandbox.js');
} catch (error) {
console.log = originalLog;
return res.status(500).json({ error: 'Failed to run code', details: error.message });
}
try {
await runCode();
const startTime = Date.now();
while (output.length === 0 && Date.now() - startTime < timeout) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
const result = output.length > 0 ? output.pop() : 'No results found.';
console.log = originalLog;
res.json({ output: result });
} catch (err) {
console.log = originalLog;
res.status(500).json({ error: 'Error while executing code', details: err.message });
}
});
const PORT = process.env.PORT || 7860;
app.listen(PORT, async () => {
console.log(`Server running on port ${PORT}`);
});
process.on('SIGINT', async () => {
process.exit(0);
});