UNPKG

@vizzly-testing/cli

Version:

Visual review platform for UI developers and designers

132 lines (131 loc) 3.84 kB
import { createServer } from 'http'; import { createServiceLogger } from '../utils/logger-factory.js'; const logger = createServiceLogger('HTTP-SERVER'); export const createHttpServer = (port, screenshotHandler, emitter = null) => { let server = null; const parseRequestBody = req => { return new Promise((resolve, reject) => { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { try { const data = JSON.parse(body); resolve(data); } catch { reject(new Error('Invalid JSON')); } }); req.on('error', reject); }); }; const handleRequest = async (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); res.setHeader('Content-Type', 'application/json'); if (req.method === 'OPTIONS') { res.statusCode = 200; res.end(); return; } if (req.method === 'GET' && req.url === '/health') { res.statusCode = 200; res.end(JSON.stringify({ status: 'ok', port: port, uptime: process.uptime() })); return; } if (req.method === 'POST' && req.url === '/screenshot') { try { const body = await parseRequestBody(req); const { buildId, name, properties, image } = body; if (!buildId || !name || !image) { res.statusCode = 400; res.end(JSON.stringify({ error: 'buildId, name, and image are required' })); return; } const result = await screenshotHandler.handleScreenshot(buildId, name, image, properties); // Emit screenshot captured event if emitter is available if (emitter && result.statusCode === 200) { emitter.emit('screenshot-captured', { name, count: screenshotHandler.getScreenshotCount?.(buildId) || 0, skipped: result.body?.skipped }); } res.statusCode = result.statusCode; res.end(JSON.stringify(result.body)); } catch (error) { logger.error('Screenshot processing error:', error); res.statusCode = 500; res.end(JSON.stringify({ error: 'Failed to process screenshot' })); } return; } res.statusCode = 404; res.end(JSON.stringify({ error: 'Not found' })); }; const start = () => { return new Promise((resolve, reject) => { server = createServer(async (req, res) => { try { await handleRequest(req, res); } catch (error) { logger.error('Server error:', error); res.statusCode = 500; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({ error: 'Internal server error' })); } }); server.listen(port, '127.0.0.1', error => { if (error) { reject(error); } else { logger.debug(`HTTP server listening on http://127.0.0.1:${port}`); resolve(); } }); server.on('error', error => { if (error.code === 'EADDRINUSE') { reject(new Error(`Port ${port} is already in use. Try a different port with --port.`)); } else { reject(error); } }); }); }; const stop = () => { if (server) { return new Promise(resolve => { server.close(() => { server = null; logger.debug('HTTP server stopped'); resolve(); }); }); } return Promise.resolve(); }; return { start, stop, getServer: () => server }; };