moved to using worker threads, can now handle more requests because of this. Also laid foundation for passing parameters
This commit is contained in:
		
							parent
							
								
									f36999721d
								
							
						
					
					
						commit
						0626a08da8
					
				
							
								
								
									
										18
									
								
								README.md
								
								
								
								
							
							
						
						
									
										18
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -1,3 +1,19 @@
 | 
				
			||||||
# motivational-picture-generator
 | 
					# motivational-picture-generator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A project to learn NodeJS, ExpressJS, and whatever else along the way.
 | 
					A project to learn NodeJS, ExpressJS, and whatever else along the way.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**THIS IS ALL WORK IN PROGRESS AND SUBJECT TO CHANGE**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To start server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					npm run dev
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Make url request to `localhost:4000/submit/{}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing with
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					ab -c 5 -t 15 http://localhost:4000/submit/\{\}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					const puppeteer = require("puppeteer");
 | 
				
			||||||
 | 
					const { scrollPageToBottom } = require("puppeteer-autoscroll-down");
 | 
				
			||||||
 | 
					const express = require("express");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { parentPort, workerData } = require("worker_threads");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const folderToServe =
 | 
				
			||||||
 | 
					    "/Users/tarasis/Programming/websites/rmcg.dev/www/FrontendMentor/newbie/social-links-profile/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const dynamicPage = express();
 | 
				
			||||||
 | 
					dynamicPage.use(express.static(folderToServe));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const dynamicServer = dynamicPage.listen(0, async () => {
 | 
				
			||||||
 | 
					    const dynamicPort = dynamicServer.address().port;
 | 
				
			||||||
 | 
					    console.log(`Dynamic server is running at http://localhost:${dynamicPort}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const browser = await puppeteer.launch();
 | 
				
			||||||
 | 
					    const page = await browser.newPage();
 | 
				
			||||||
 | 
					    await page.goto(`http://localhost:${dynamicPort}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await page.waitForResponse((response) => response.status() === 200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await scrollPageToBottom(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const screenshotBuffer = await page.screenshot({ fullPage: true });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // other option is just to save the file to disk
 | 
				
			||||||
 | 
					    // await page.screenshot({ path: 'example.png' });
 | 
				
			||||||
 | 
					    // Close the browser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await browser.close();
 | 
				
			||||||
 | 
					    console.log(`Closing dynamic server http://localhost:${dynamicPort}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await dynamicServer.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parentPort.postMessage({
 | 
				
			||||||
 | 
					        type: "image",
 | 
				
			||||||
 | 
					        data: screenshotBuffer,
 | 
				
			||||||
 | 
					        port: dynamicPort,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										76
									
								
								index.mjs
								
								
								
								
							
							
						
						
									
										76
									
								
								index.mjs
								
								
								
								
							| 
						 | 
					@ -1,49 +1,61 @@
 | 
				
			||||||
import puppeteer from "puppeteer";
 | 
					 | 
				
			||||||
import { scrollPageToBottom } from "puppeteer-autoscroll-down";
 | 
					 | 
				
			||||||
import express from "express";
 | 
					import express from "express";
 | 
				
			||||||
import "dotenv/config";
 | 
					import "dotenv/config";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const folderToServe = "/Users/tarasis/Programming/websites/rmcg.dev/www/";
 | 
					import { Worker, isMainThread, parentPort, workerData } from "worker_threads";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import fs from "fs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const port = process.env.PORT || 4000;
 | 
					const port = process.env.PORT || 4000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const app = express();
 | 
					const app = express();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app.use(express.static(folderToServe));
 | 
					app.use(express.static("www"));
 | 
				
			||||||
app.get("/screenshot", async (req, res) => {
 | 
					 | 
				
			||||||
    const dynamicPage = express();
 | 
					 | 
				
			||||||
    dynamicPage.use(express.static(folderToServe));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const dynamicServer = dynamicPage.listen(0, async () => {
 | 
					app.get("/submit/:mpgParams", (req, res) => {
 | 
				
			||||||
        const dynamicPort = dynamicServer.address().port;
 | 
					    // console.log("🚀 ~ app.get ~ req:", req);
 | 
				
			||||||
        console.log(
 | 
					    // Get any supplied parameters, this keeps it clean
 | 
				
			||||||
            `Dynamic server is running at http://localhost:${dynamicPort}`
 | 
					    // if I pass more parameters in the future
 | 
				
			||||||
        );
 | 
					    const mpgParams = req.query.mpgParams;
 | 
				
			||||||
 | 
					    console.log("🚀 ~ app.get ~ mpgParams:", mpgParams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const browser = await puppeteer.launch();
 | 
					    const worker = new Worker("./image-generator.cjs", {
 | 
				
			||||||
        const page = await browser.newPage();
 | 
					        workerData: {
 | 
				
			||||||
        await page.goto(`http://localhost:${dynamicPort}`);
 | 
					            mpgParams,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await page.waitForResponse((response) => response.status() === 200);
 | 
					    // nicer would be to return a link the user
 | 
				
			||||||
 | 
					    // can click to download the image
 | 
				
			||||||
 | 
					    // or better yet dynamically load it into the original page in an iframe or ssg thing
 | 
				
			||||||
 | 
					    // but that might require moving project
 | 
				
			||||||
 | 
					    // to a framework like react/astro
 | 
				
			||||||
 | 
					    worker.on("message", (message) => {
 | 
				
			||||||
 | 
					        if (message.type === "image") {
 | 
				
			||||||
 | 
					            res.writeHead(200, {
 | 
				
			||||||
 | 
					                "Content-Type": "image/png",
 | 
				
			||||||
 | 
					                "Content-Length": message.data.length,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            res.end(message.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await scrollPageToBottom(page);
 | 
					            // save the image - temporary for now
 | 
				
			||||||
 | 
					            // fs.writeFileSync(
 | 
				
			||||||
 | 
					            //     `received_image-${message.port}.png`,
 | 
				
			||||||
 | 
					            //     message.data
 | 
				
			||||||
 | 
					            // );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const screenshotBuffer = await page.screenshot({ fullPage: true });
 | 
					    worker.on("error", (err) => {
 | 
				
			||||||
 | 
					        // Handle errors from the worker
 | 
				
			||||||
 | 
					        console.error(err);
 | 
				
			||||||
 | 
					        res.status(500).send("Internal Server Error");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Respond with the image
 | 
					    worker.on("exit", (code) => {
 | 
				
			||||||
        res.writeHead(200, {
 | 
					        if (code !== 0) {
 | 
				
			||||||
            "Content-Type": "image/png",
 | 
					            // Handle non-zero exit codes
 | 
				
			||||||
            "Content-Length": screenshotBuffer.length,
 | 
					            console.error(new Error(`Worker stopped with exit code ${code}`));
 | 
				
			||||||
        });
 | 
					        }
 | 
				
			||||||
        res.end(screenshotBuffer);
 | 
					 | 
				
			||||||
        // other option is just to save the file to disk
 | 
					 | 
				
			||||||
        // await page.screenshot({ path: 'example.png' });
 | 
					 | 
				
			||||||
        // Close the browser
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await browser.close();
 | 
					 | 
				
			||||||
        console.log(`Closing dynamic server http://localhost:${dynamicPort}`);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await dynamicServer.close();
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@
 | 
				
			||||||
        "dotenv": "^16.4.5",
 | 
					        "dotenv": "^16.4.5",
 | 
				
			||||||
        "express": "^4.18.3",
 | 
					        "express": "^4.18.3",
 | 
				
			||||||
        "puppeteer": "^22.4.0",
 | 
					        "puppeteer": "^22.4.0",
 | 
				
			||||||
        "puppeteer-autoscroll-down": "^2.0.0"
 | 
					        "puppeteer-autoscroll-down": "^1.1.2"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@babel/code-frame": {
 | 
					    "node_modules/@babel/code-frame": {
 | 
				
			||||||
| 
						 | 
					@ -1498,11 +1498,11 @@
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/puppeteer-autoscroll-down": {
 | 
					    "node_modules/puppeteer-autoscroll-down": {
 | 
				
			||||||
      "version": "2.0.0",
 | 
					      "version": "1.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/puppeteer-autoscroll-down/-/puppeteer-autoscroll-down-2.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/puppeteer-autoscroll-down/-/puppeteer-autoscroll-down-1.1.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-Bo5ADSo1t5u36IxY4x/EgS6kNQqMXfTNRSh5CSR5bpoTTOpzE+HE0LZ5xIlqzAfpRjaPtsOd+2lRQiPeAKQlHA==",
 | 
					      "integrity": "sha512-SSzxBf6Iu2zn6NNqZO1XlU8cqbjVOzhlTh38xLU42srNZjrDXkIAhKandScM0ZwueVOtOs4xSY0FN2S6whlFSA==",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=18"
 | 
					        "node": ">=12"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/puppeteer-core": {
 | 
					    "node_modules/puppeteer-core": {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,6 @@
 | 
				
			||||||
    "dotenv": "^16.4.5",
 | 
					    "dotenv": "^16.4.5",
 | 
				
			||||||
    "express": "^4.18.3",
 | 
					    "express": "^4.18.3",
 | 
				
			||||||
    "puppeteer": "^22.4.0",
 | 
					    "puppeteer": "^22.4.0",
 | 
				
			||||||
    "puppeteer-autoscroll-down": "^2.0.0"
 | 
					    "puppeteer-autoscroll-down": "^1.1.2"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
				
			||||||
 | 
					    <title>Movitvational Picture Generator</title>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <h1>Hello World</h1>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue