chromium / index.js
Johnsteve Costanos
Fix Chrome stability: add --no-zygote and other flags to prevent OOM-denied crashes
d8d1a41
Raw
History Blame Contribute Delete
3.38 kB
import { spawn } from 'child_process';
import { createServer } from 'http';
import WebSocket, { WebSocketServer } from 'ws';
const CHROME_PORT = 9222;
const PORT = 7860;
let chrome;
function startChrome() {
if (chrome) chrome.kill();
console.log('Starting Chrome...');
chrome = spawn('chromium', [
'--headless=new', '--no-sandbox', '--disable-gpu',
`--remote-debugging-port=${CHROME_PORT}`,
'--remote-debugging-address=127.0.0.1',
'--disable-dev-shm-usage',
'--no-zygote',
'--window-size=1280,800',
'--disable-breakpad',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-component-extensions-with-background-pages',
'--no-first-run',
'--no-default-browser-check',
'--disable-sync',
'--disable-component-update',
'--disable-default-apps',
'--disable-hang-monitor',
], { stdio: ['ignore', 'pipe', 'pipe'] });
chrome.stderr.on('data', d => console.error('CHROME:', d.toString().trimEnd()));
chrome.on('exit', (code, sig) => {
console.error('Chrome died exit=' + code + ' sig=' + sig + ', restarting in 3s...');
setTimeout(startChrome, 3000);
});
}
async function waitForChrome(retries = 30) {
for (let i = 0; i < retries; i++) {
try {
const r = await fetch(`http://127.0.0.1:${CHROME_PORT}/json/version`);
if (r.ok) {
const j = await r.json();
console.log('Chrome ready, browser:', j.webSocketDebuggerUrl);
return;
}
} catch {}
await new Promise(r => setTimeout(r, 1000));
}
console.error('Chrome not ready after', retries, 'retries');
}
startChrome();
function wsProto(req) {
return req.socket.encrypted || req.headers['x-forwarded-proto'] === 'https' ? 'wss' : 'ws';
}
const server = createServer(async (req, res) => {
if (req.url === '/' || req.url === '/health') {
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ status: 'ok', chrome: 'running' }));
return;
}
try {
const r = await fetch(`http://127.0.0.1:${CHROME_PORT}${req.url}`);
const text = await r.text();
const h = { 'content-type': r.headers.get('content-type') || 'application/json' };
res.writeHead(r.status, h);
res.end(text.replace(
new RegExp(`ws://127\\.0\\.0\\.1:${CHROME_PORT}`, 'g'),
`${wsProto(req)}://${req.headers.host}`
));
} catch (e) {
res.writeHead(502);
res.end(JSON.stringify({ error: e.message }));
}
});
new WebSocketServer({ server }).on('connection', (ws, req) => {
const url = req.url || '/';
const target = `ws://127.0.0.1:${CHROME_PORT}${url}`;
const cws = new WebSocket(target);
let cwsReady = false;
const pending = [];
ws.on('message', (d) => {
const str = d.toString();
if (cwsReady) { try { cws.send(str); } catch {} }
else { pending.push(str); }
});
ws.on('close', () => { try { cws.close(); } catch {} });
cws.on('open', () => {
cwsReady = true;
for (const s of pending) try { cws.send(s); } catch {}
pending.length = 0;
cws.on('message', d => { try { ws.send(d.toString()); } catch {} });
cws.on('close', () => { try { ws.close(); } catch {} });
});
cws.on('error', () => { try { ws.close(1011); } catch {} });
});
await waitForChrome();
server.listen(PORT, '0.0.0.0', () => {
console.log(`WSS proxy on 0.0.0.0:${PORT}`);
});