feature/IO-3052-Skia-Canvas-Handler: Merge release and fix PR's

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-12-05 12:01:58 -08:00
8 changed files with 104 additions and 49 deletions

View File

@@ -5,6 +5,9 @@ const Chart = require("chart.js/auto");
const { backgroundColors, borderColors } = require("./canvas-colors");
const { defaultsDeep, isNumber } = require("lodash");
let isProcessing = false;
const requestQueue = [];
try {
FontLibrary.use("Montserrat", [
"/usr/share/fonts/Montserrat-Regular.ttf",
@@ -60,69 +63,81 @@ const getChartConfiguration = (keys, values, override) => {
return defaultsDeep(override || {}, defaultConfiguration);
};
exports.canvastest = function (req, res) {
res.status(200).send("OK");
};
exports.canvas = function (req, res) {
const { logger } = req;
const { w, h, values, keys, override } = req.body;
logger.log("inbound-canvas-creation", "debug", "jsr", null, { w, h, values, keys, override });
// Set the default Width and Height
let [width, height] = [500, 275];
// Allow for custom width and height
if (isNumber(w)) {
width = w;
}
if (isNumber(h)) {
height = h;
}
const configuration = getChartConfiguration(keys, values, override);
res.status(200).send(
(() => {
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d");
new Chart(ctx, configuration);
return canvas.toDataURL();
})()
);
};
exports.canvasSkia = async function (req, res) {
const processCanvasRequest = async (req, res, isSkia = false) => {
const { logger } = req;
const { w, h, values, keys, override } = req.body;
// Log incoming request for debugging
logger.log("inbound-canvas-creation", "debug", "jsr", null, { w, h, values, keys, override });
// Default width and height
const width = typeof w === "number" && w > 0 ? w : 500;
const height = typeof h === "number" && h > 0 ? h : 275;
const width = isNumber(w) && w > 0 ? w : 500;
const height = isNumber(h) && h > 0 ? h : 275;
const configuration = getChartConfiguration(keys, values, override);
try {
// Create a canvas and get the 2D rendering context
const canvas = new Canvas(width, height);
const canvas = isSkia ? new Canvas(width, height) : createCanvas(width, height);
const ctx = canvas.getContext("2d");
// Render the chart
new Chart(ctx, configuration);
const chart = new Chart(ctx, configuration);
// Convert the canvas to a Base64-encoded image
const chartImage = (await canvas.toBuffer("image/png")).toString("base64");
const dataURL = `data:image/png;base64,${chartImage}`;
// Generate and send the image
const chartImage = isSkia
? (await canvas.toBuffer("image/png")).toString("base64")
: canvas.toDataURL();
// Send the Base64-encoded image as the response
res.status(200).send(dataURL);
chart.destroy();
res.status(200).send(isSkia ? `data:image/png;base64,${chartImage}` : chartImage);
} catch (error) {
// Log and handle rendering errors
logger.log("canvas-error", "error", "jsr", null, { error: error.message });
res.status(500).send("Failed to generate canvas.");
}
};
const processNextInQueue = async () => {
if (requestQueue.length === 0) {
isProcessing = false;
return;
}
const { req, res, isSkia } = requestQueue.shift();
await processCanvasRequest(req, res, isSkia);
processNextInQueue();
};
exports.canvastest = function (req, res) {
res.status(200).send("OK");
};
exports.canvas = async function (req, res) {
if (isProcessing) {
if (requestQueue.length >= 100) {
// Set a maximum queue size
return res.status(503).send("Server is busy. Please try again later.");
}
requestQueue.push({ req, res, isSkia: false });
req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
return;
}
isProcessing = true;
await processCanvasRequest(req, res, false);
processNextInQueue();
};
exports.canvasSkia = async function (req, res) {
if (isProcessing) {
if (requestQueue.length >= 100) {
// Set a maximum queue size
return res.status(503).send("Server is busy. Please try again later.");
}
requestQueue.push({ req, res, isSkia: true });
req.logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
return;
}
isProcessing = true;
await processCanvasRequest(req, res, true);
processNextInQueue();
};