playwright / app.js
rynekoo's picture
Update app.js
315de5e verified
Raw History Blame Contribute Delete
7.99 kB
const express = require('express');
const { chromium } = require('playwright');
const cors = require('cors');
const { NodeVM } = require('vm2');
const axios = require('axios');
const app = express();
const PORT = process.env.PORT || 7860;
app.set('json spaces', 2);
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
next();
});
app.get('/', (req, res) => {
res.json({
success: true,
endpoints: {
playwright_v1: 'POST /v1',
playwright_v2: 'POST /v2',
playwright_v3: 'POST /v3'
},
timestamp: new Date().toISOString()
});
});
app.post('/v1', async (req, res) => {
const { code, timeout = 300000 } = req.body;
if (!code) {
return res.status(400).json({
error: {
message: 'Code is required',
type: 'invalid_request_error'
}
});
}
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 },
},
},
});
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: {
message: 'Failed to run code',
details: error.message,
type: 'execution_error'
}
});
}
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 output found.';
console.log = originalLog;
res.json({ data: result });
} catch (err) {
console.log = originalLog;
res.status(500).json({
error: {
message: 'Error while executing code',
details: err.message,
type: 'execution_error'
}
});
}
});
app.post('/v2', async (req, res) => {
const { code, timeout = 300000 } = req.body;
if (!code) {
return res.status(400).json({
error: {
message: 'Code is required',
type: 'invalid_request_error'
}
});
}
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);
};
let runCode;
try {
runCode = eval(`
(async () => {
${code}
})();
`);
} catch (error) {
console.log = originalLog;
return res.status(500).json({
error: {
message: 'Failed to run code',
details: error.message,
type: 'execution_error'
}
});
}
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 output found.';
console.log = originalLog;
res.json({ data: result });
} catch (err) {
console.log = originalLog;
res.status(500).json({
error: {
message: 'Error while executing code',
details: err.message,
type: 'execution_error'
}
});
}
});
app.post('/v3', async (req, res) => {
const { code, language = 'javascript' } = req.body;
if (!code) {
return res.status(400).json({
error: {
message: 'Code is required',
type: 'invalid_request_error'
}
});
}
const MAX_RETRIES = 3;
let lastMessage = null;
let lastDetails = null;
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
const { data: cf } = await axios.post('https://rynekoo-cf.hf.space/action', {
url: 'https://try.playwright.tech/',
siteKey: '0x4AAAAAAA_K0T_2LZ0rgUtv',
mode: 'turnstile-min'
});
if (!cf?.data?.token) throw new Error('Failed to get cf token.');
const { data } = await axios.post('https://try.playwright.tech/service/control/run', {
code,
language,
token: cf.data.token
}, {
headers: {
origin: 'https://try.playwright.tech',
referer: 'https://try.playwright.tech/',
'user-agent': 'Mozilla/5.0 (Linux; Android 15; SM-F958 Build/AP3A.240905.015) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.86 Mobile Safari/537.36'
}
});
const isTimeout = data?.error === 'Execution timeout!';
const isProtocolError = typeof data?.output === 'string' && data.output.includes('Protocol error');
if ((isTimeout || isProtocolError) && attempt < MAX_RETRIES) {
lastMessage = data?.error || 'Error while executing code';
lastDetails = data?.output || null;
continue;
}
return res.json({ data: data.output });
} catch (error) {
const errData = error.response?.data;
const isTimeout = errData?.error === 'Execution timeout!';
const isProtocolError = typeof errData?.output === 'string' && errData.output.includes('Protocol error');
lastMessage = errData?.error || 'Error while executing code';
lastDetails = errData?.output || null;
if ((isTimeout || isProtocolError) && attempt < MAX_RETRIES) {
continue;
}
return res.status(500).json({
error: {
message: lastMessage,
details: lastDetails,
type: 'execution_error'
}
});
}
}
res.status(500).json({
error: {
message: lastMessage,
details: lastDetails,
type: 'execution_error'
}
});
});
app.use((err, req, res, next) => {
console.error('Error:', err.message);
res.status(err.status || 500).json({
error: {
message: err.message || 'Internal server error',
type: 'api_error'
}
});
});
app.use((req, res) => {
res.status(404).json({
error: {
message: 'Not found',
type: 'invalid_request_error'
}
});
});
function startServer() {
app.listen(PORT, () => {
console.log(`Playwright API Server running on http://localhost:${PORT}`);
console.log('\nAvailable endpoints:');
console.log(` POST http://localhost:${PORT}/v1`);
console.log(` POST http://localhost:${PORT}/v2`);
console.log(` POST http://localhost:${PORT}/v3`);
});
}
process.on('SIGINT', () => {
console.log('\nShutting down...');
process.exit(0);
});
startServer();