feature/IO-3096-Global-Notification-Preferences - Upgrade Node to 22 / Remove canvas and replace it 100% with canvas-skia
This commit is contained in:
@@ -3,7 +3,7 @@ FROM amazonlinux:2023
|
|||||||
|
|
||||||
# Install Git and Node.js (Amazon Linux 2023 uses the DNF package manager)
|
# Install Git and Node.js (Amazon Linux 2023 uses the DNF package manager)
|
||||||
RUN dnf install -y git \
|
RUN dnf install -y git \
|
||||||
&& curl -sL https://rpm.nodesource.com/setup_20.x | bash - \
|
&& curl -sL https://rpm.nodesource.com/setup_22.x | bash - \
|
||||||
&& dnf install -y nodejs \
|
&& dnf install -y nodejs \
|
||||||
&& dnf clean all
|
&& dnf clean all
|
||||||
|
|
||||||
|
|||||||
54
package-lock.json
generated
54
package-lock.json
generated
@@ -23,7 +23,6 @@
|
|||||||
"better-queue": "^3.8.12",
|
"better-queue": "^3.8.12",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
"body-parser": "^1.20.3",
|
"body-parser": "^1.20.3",
|
||||||
"canvas": "^2.11.2",
|
|
||||||
"chart.js": "^4.4.6",
|
"chart.js": "^4.4.6",
|
||||||
"cloudinary": "^2.5.1",
|
"cloudinary": "^2.5.1",
|
||||||
"compression": "^1.7.5",
|
"compression": "^1.7.5",
|
||||||
@@ -4224,21 +4223,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/canvas": {
|
|
||||||
"version": "2.11.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
|
|
||||||
"integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@mapbox/node-pre-gyp": "^1.0.0",
|
|
||||||
"nan": "^2.17.0",
|
|
||||||
"simple-get": "^3.0.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cargo-cp-artifact": {
|
"node_modules/cargo-cp-artifact": {
|
||||||
"version": "0.1.9",
|
"version": "0.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/cargo-cp-artifact/-/cargo-cp-artifact-0.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/cargo-cp-artifact/-/cargo-cp-artifact-0.1.9.tgz",
|
||||||
@@ -4971,18 +4955,6 @@
|
|||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/decompress-response": {
|
|
||||||
"version": "4.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
|
|
||||||
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"mimic-response": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/deeks": {
|
"node_modules/deeks": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/deeks/-/deeks-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/deeks/-/deeks-3.1.0.tgz",
|
||||||
@@ -8232,18 +8204,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mimic-response": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minimalistic-assert": {
|
"node_modules/minimalistic-assert": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||||
@@ -8372,7 +8332,8 @@
|
|||||||
"version": "2.22.0",
|
"version": "2.22.0",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz",
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz",
|
||||||
"integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==",
|
"integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/natural-compare": {
|
"node_modules/natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
@@ -9818,17 +9779,6 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/simple-get": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"decompress-response": "^4.2.0",
|
|
||||||
"once": "^1.3.1",
|
|
||||||
"simple-concat": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/simple-swizzle": {
|
"node_modules/simple-swizzle": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
"better-queue": "^3.8.12",
|
"better-queue": "^3.8.12",
|
||||||
"bluebird": "^3.7.2",
|
"bluebird": "^3.7.2",
|
||||||
"body-parser": "^1.20.3",
|
"body-parser": "^1.20.3",
|
||||||
"canvas": "^2.11.2",
|
|
||||||
"chart.js": "^4.4.6",
|
"chart.js": "^4.4.6",
|
||||||
"cloudinary": "^2.5.1",
|
"cloudinary": "^2.5.1",
|
||||||
"compression": "^1.7.5",
|
"compression": "^1.7.5",
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const { createCanvas } = require("canvas");
|
|
||||||
const { Canvas, FontLibrary } = require("skia-canvas");
|
const { Canvas, FontLibrary } = require("skia-canvas");
|
||||||
const Chart = require("chart.js/auto");
|
const Chart = require("chart.js/auto");
|
||||||
|
|
||||||
@@ -65,7 +64,7 @@ const getChartConfiguration = (keys, values, override) => {
|
|||||||
return defaultsDeep(override || {}, defaultConfiguration);
|
return defaultsDeep(override || {}, defaultConfiguration);
|
||||||
};
|
};
|
||||||
|
|
||||||
const processCanvasRequest = async (req, res, isSkia = false) => {
|
const processCanvasRequest = async (req, res) => {
|
||||||
const { logger } = req;
|
const { logger } = req;
|
||||||
const { w, h, values, keys, override } = req.body;
|
const { w, h, values, keys, override } = req.body;
|
||||||
|
|
||||||
@@ -77,7 +76,6 @@ const processCanvasRequest = async (req, res, isSkia = false) => {
|
|||||||
|
|
||||||
const configuration = getChartConfiguration(keys, values, override);
|
const configuration = getChartConfiguration(keys, values, override);
|
||||||
|
|
||||||
// Placeholders to allow fine control over GAC
|
|
||||||
let canvas = null;
|
let canvas = null;
|
||||||
let ctx = null;
|
let ctx = null;
|
||||||
let chart = null;
|
let chart = null;
|
||||||
@@ -85,16 +83,15 @@ const processCanvasRequest = async (req, res, isSkia = false) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Create the canvas
|
// Create the canvas
|
||||||
canvas = isSkia ? new Canvas(width, height) : createCanvas(width, height);
|
canvas = new Canvas(width, height);
|
||||||
ctx = canvas.getContext("2d");
|
ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
// Render the chart
|
// Render the chart
|
||||||
chart = new Chart(ctx, configuration);
|
chart = new Chart(ctx, configuration);
|
||||||
|
|
||||||
// Generate and send the image
|
// Generate and send the image
|
||||||
chartImage = isSkia ? (await canvas.toBuffer("image/png")).toString("base64") : canvas.toDataURL();
|
chartImage = (await canvas.toBuffer("image/png")).toString("base64");
|
||||||
|
res.status(200).send(`data:image/png;base64,${chartImage}`);
|
||||||
res.status(200).send(isSkia ? `data:image/png;base64,${chartImage}` : chartImage);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Log the error and send the response
|
// Log the error and send the response
|
||||||
logger.log("canvas-error", "error", "jsr", null, { error: error.message });
|
logger.log("canvas-error", "error", "jsr", null, { error: error.message });
|
||||||
@@ -104,27 +101,27 @@ const processCanvasRequest = async (req, res, isSkia = false) => {
|
|||||||
if (chart) {
|
if (chart) {
|
||||||
chart.destroy();
|
chart.destroy();
|
||||||
}
|
}
|
||||||
ctx = null; // Explicitly nullify for garbage collection
|
ctx = null;
|
||||||
canvas = null; // Explicitly nullify for garbage collection
|
canvas = null;
|
||||||
chartImage = null;
|
chartImage = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const enqueueRequest = (req, res, isSkia) => {
|
const enqueueRequest = (req, res) => {
|
||||||
if (requestQueue.length >= CANVAS_QUEUE_LIMIT) {
|
if (requestQueue.length >= CANVAS_QUEUE_LIMIT) {
|
||||||
res.status(503).send("Server is busy. Please try again later.");
|
res.status(503).send("Server is busy. Please try again later.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
requestQueue.push({ req, res, isSkia });
|
requestQueue.push({ req, res });
|
||||||
req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
|
req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const processNextInQueue = async () => {
|
const processNextInQueue = async () => {
|
||||||
while (requestQueue.length > 0) {
|
while (requestQueue.length > 0) {
|
||||||
const { req, res, isSkia } = requestQueue.shift();
|
const { req, res } = requestQueue.shift();
|
||||||
try {
|
try {
|
||||||
await processCanvasRequest(req, res, isSkia);
|
await processCanvasRequest(req, res);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("canvas-queue-error", "error", "jsr", null, { error: err.message });
|
console.error("canvas-queue-error", "error", "jsr", null, { error: err.message });
|
||||||
}
|
}
|
||||||
@@ -137,13 +134,7 @@ exports.canvastest = function (req, res) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.canvas = async (req, res) => {
|
exports.canvas = async (req, res) => {
|
||||||
if (isProcessing || !enqueueRequest(req, res, false)) return;
|
if (isProcessing || !enqueueRequest(req, res)) return;
|
||||||
isProcessing = true;
|
|
||||||
processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.canvasSkia = async (req, res) => {
|
|
||||||
if (isProcessing || !enqueueRequest(req, res, true)) return;
|
|
||||||
isProcessing = true;
|
isProcessing = true;
|
||||||
processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
|
processNextInQueue().catch((err) => console.error("canvas-processing-error", { error: err.message }));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ const express = require("express");
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { inlinecss } = require("../render/inlinecss");
|
const { inlinecss } = require("../render/inlinecss");
|
||||||
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
||||||
const { canvas, canvasSkia } = require("../render/canvas-handler");
|
const { canvas } = require("../render/canvas-handler");
|
||||||
const validateCanvasInputMiddleware = require("../middleware/validateCanvasInputMiddleware");
|
const validateCanvasInputMiddleware = require("../middleware/validateCanvasInputMiddleware");
|
||||||
|
|
||||||
// Define the route for inline CSS rendering
|
// Define the route for inline CSS rendering
|
||||||
router.post("/inlinecss", validateFirebaseIdTokenMiddleware, inlinecss);
|
router.post("/inlinecss", validateFirebaseIdTokenMiddleware, inlinecss);
|
||||||
router.post("/canvas", [validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware], canvas);
|
router.post("/canvas-skia", validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware, canvas);
|
||||||
router.post("/canvas-skia", [validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware], canvasSkia);
|
router.post("/canvas", validateFirebaseIdTokenMiddleware, validateCanvasInputMiddleware, canvas);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
Reference in New Issue
Block a user