Compare commits

..

3 Commits

8 changed files with 199 additions and 8 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
### Personal rmcg
screenshot.png
# ---> Node # ---> Node
# Logs # Logs
logs logs

View File

@ -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/\{\}
```

View File

@ -0,0 +1,52 @@
import puppeteer from "puppeteer";
import { scrollPageToBottom } from "puppeteer-autoscroll-down";
import express from "express";
import "dotenv/config";
const folderToServe = "/Users/tarasis/Programming/websites/rmcg.dev/www/";
const port = process.env.PORT || 4000;
const app = express();
app.use(express.static(folderToServe));
app.get("/screenshot", async (req, res) => {
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 });
// Respond with the image
res.writeHead(200, {
"Content-Type": "image/png",
"Content-Length": screenshotBuffer.length,
});
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();
});
});
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});

41
image-generator.cjs Normal file
View File

@ -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,
});
});

64
index.mjs Normal file
View File

@ -0,0 +1,64 @@
import express from "express";
import "dotenv/config";
import { Worker, isMainThread, parentPort, workerData } from "worker_threads";
import fs from "fs";
const port = process.env.PORT || 4000;
const app = express();
app.use(express.static("www"));
app.get("/submit/:mpgParams", (req, res) => {
// console.log("🚀 ~ app.get ~ req:", req);
// Get any supplied parameters, this keeps it clean
// if I pass more parameters in the future
const mpgParams = req.query.mpgParams;
console.log("🚀 ~ app.get ~ mpgParams:", mpgParams);
const worker = new Worker("./image-generator.cjs", {
workerData: {
mpgParams,
},
});
// 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);
// save the image - temporary for now
// fs.writeFileSync(
// `received_image-${message.port}.png`,
// message.data
// );
}
});
worker.on("error", (err) => {
// Handle errors from the worker
console.error(err);
res.status(500).send("Internal Server Error");
});
worker.on("exit", (code) => {
if (code !== 0) {
// Handle non-zero exit codes
console.error(new Error(`Worker stopped with exit code ${code}`));
}
});
});
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});

10
package-lock.json generated
View File

@ -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": {

View File

@ -4,16 +4,17 @@
"description": "A project to learn NodeJS, ExpressJS, and whatever else along the way.", "description": "A project to learn NodeJS, ExpressJS, and whatever else along the way.",
"main": "index.mjs", "main": "index.mjs",
"scripts": { "scripts": {
"dev": "nodemon index.mjs",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"type": "Modules", "type": "module",
"dependencies": { "dependencies": {
"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"
} }
} }

14
www/index.html Normal file
View File

@ -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>