import bodyParser from "body-parser"; import express, { Express } from "express"; import { Server } from "net"; import { debugLogger } from "../logger"; import { ScreenshotRenderer } from "../screenshot-renderer/api"; import { ScreenshotServer } from "./api"; const logDebug = debugLogger("LocalScreenshotServer"); /** * A local server with a /render POST endpoint, which takes a payload such as * * ```json * { * "url": "https://www.google.com" * } * ``` * * and returns a PNG screenshot of the URL. */ export class LocalScreenshotServer implements ScreenshotServer { private readonly app: Express; private server: Server | null = null; constructor( private readonly renderer: ScreenshotRenderer, private readonly port: number ) { this.app = express(); this.app.use(bodyParser.json()); this.app.post("/render", async (req, res) => { const { name, url, viewport } = req.body; try { const screenshot = await (viewport ? this.renderer.render(name, url, viewport) : this.renderer.render(name, url)); if (screenshot) { res.contentType("image/png"); res.end(screenshot); } else { res.status(204); res.end(); } } catch (e) { res.status(500); // eslint-disable-next-line no-console console.error(e); res.end(e.message || `Unable to render a screenshot of ${url}`); } }); } async start() { logDebug(`start() initiated.`); logDebug(`Starting renderer.`); await this.renderer.start(); logDebug(`Renderer started.`); logDebug(`Attempting to listen on port ${this.port}.`); await new Promise((resolve) => { this.server = this.app.listen(this.port, resolve); }); logDebug(`Successfully listening on port ${this.port}.`); } async stop() { logDebug(`stop() initiated.`); const { server } = this; if (!server) { throw new Error( "Server is not running! Please make sure that start() was called." ); } logDebug(`Attempting to shutdown server.`); await new Promise((resolve, reject) => { server.close((err) => (err ? reject(err) : resolve())); }); logDebug(`Successfully shutdown server.`); logDebug(`Stopping renderer.`); await this.renderer.stop(); logDebug(`Renderer stopped.`); } }