Update configuration, add dependencies, and enhance socket event handling
Some checks failed
farmcontrol/farmcontrol-ws/pipeline/head There was a failure building this commit
Some checks failed
farmcontrol/farmcontrol-ws/pipeline/head There was a failure building this commit
- Changed log level in config.json from "debug" to "trace" for more detailed logging. - Added new dependencies "pdf-to-img" and "sharp" in package.json for image processing capabilities. - Introduced 'renderTemplateJPG' event handling in SocketHost and SocketUser classes to support JPG rendering. - Implemented the renderJPG method in TemplateManager for converting templates to JPG format, including error handling and logging.
This commit is contained in:
parent
53b5924767
commit
c2372f661e
@ -35,9 +35,11 @@
|
||||
"nanoid": "^5.1.6",
|
||||
"node-cache": "^5.1.2",
|
||||
"object-hash": "^3.0.0",
|
||||
"pdf-to-img": "^6.1.0",
|
||||
"posthtml": "^0.16.7",
|
||||
"puppeteer": "^24.31.0",
|
||||
"redis": "^5.10.0",
|
||||
"sharp": "^0.34.5",
|
||||
"socket.io": "^4.8.1",
|
||||
"socket.io-adapter-mongo": "^2.0.5",
|
||||
"socketio-jwt": "^4.6.2"
|
||||
|
||||
@ -7,40 +7,40 @@ const subJobSchema = new mongoose.Schema({
|
||||
printer: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'printer',
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
job: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'job',
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
moonrakerJobId: {
|
||||
type: String,
|
||||
required: false
|
||||
required: false,
|
||||
},
|
||||
gcodeFile: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'gcodeFile',
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
state: {
|
||||
type: { required: true, type: String },
|
||||
progress: { required: false, type: Number }
|
||||
progress: { required: false, type: Number },
|
||||
},
|
||||
number: {
|
||||
type: Number,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
default: Date.now,
|
||||
},
|
||||
updatedAt: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
default: Date.now,
|
||||
},
|
||||
startedAt: { required: false, type: Date, default: null },
|
||||
finishedAt: { required: false, type: Date, default: null }
|
||||
finishedAt: { required: false, type: Date, default: null },
|
||||
});
|
||||
|
||||
subJobSchema.index({ moonrakerJobId: 'text', 'state.type': 'text' });
|
||||
|
||||
@ -68,6 +68,10 @@ export class SocketHost {
|
||||
'renderTemplatePDF',
|
||||
this.handleRenderTemplatePDFEvent.bind(this)
|
||||
);
|
||||
this.socket.on(
|
||||
'renderTemplateJPG',
|
||||
this.handleRenderTemplateJPGEvent.bind(this)
|
||||
);
|
||||
this.socket.on('objectEvent', this.handleObjectEventEvent.bind(this));
|
||||
this.socket.on('disconnect', this.handleDisconnect.bind(this));
|
||||
}
|
||||
@ -262,6 +266,16 @@ export class SocketHost {
|
||||
callback(result);
|
||||
}
|
||||
|
||||
async handleRenderTemplateJPGEvent(data, callback) {
|
||||
const result = await this.templateManager.renderJPG(
|
||||
data._id,
|
||||
data.content,
|
||||
data.object,
|
||||
{ width: data.width }
|
||||
);
|
||||
callback(result);
|
||||
}
|
||||
|
||||
async setDevicesState(state, online, connectedAt) {
|
||||
logger.info('Setting devices state to', state, 'and online to', online);
|
||||
|
||||
|
||||
@ -93,6 +93,10 @@ export class SocketUser {
|
||||
'renderTemplatePDF',
|
||||
this.handleRenderTemplatePDFEvent.bind(this)
|
||||
);
|
||||
this.socket.on(
|
||||
'renderTemplateJPG',
|
||||
this.handleRenderTemplateJPGEvent.bind(this)
|
||||
);
|
||||
this.socket.on(
|
||||
'generateHostOtp',
|
||||
this.handleGenerateHostOtpEvent.bind(this)
|
||||
@ -342,6 +346,26 @@ export class SocketUser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handleRenderTemplateJPGEvent(data, callback) {
|
||||
try {
|
||||
const result = await this.templateManager.renderJPG(
|
||||
data._id,
|
||||
data.content,
|
||||
data.object,
|
||||
{ width: data.width }
|
||||
);
|
||||
if (typeof callback === 'function') {
|
||||
callback(result);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Render template JPG event error:', err);
|
||||
if (typeof callback === 'function') {
|
||||
callback({ error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handleGenerateHostOtpEvent(data, callback) {
|
||||
const result = await generateHostOTP(data._id);
|
||||
callback(result);
|
||||
|
||||
78
src/templates/pdfUtils.js
Normal file
78
src/templates/pdfUtils.js
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* PDF conversion utilities loaded on demand so startup
|
||||
* does not require ESM-only pdf-to-img at module load time.
|
||||
*/
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
async function importPackage(name) {
|
||||
const packagePath = require.resolve(name);
|
||||
return import(pathToFileURL(packagePath).href);
|
||||
}
|
||||
|
||||
function resolveDefault(module) {
|
||||
return module?.default ?? module;
|
||||
}
|
||||
|
||||
export async function convertPDFToImage(pdfInput, options = {}) {
|
||||
const [pdfToImgModule, sharpModule] = await Promise.all([
|
||||
importPackage('pdf-to-img'),
|
||||
importPackage('sharp')
|
||||
]);
|
||||
const { pdf } = pdfToImgModule;
|
||||
const sharp = resolveDefault(sharpModule);
|
||||
|
||||
try {
|
||||
const { width, height, page_numbers, scale = 2, ...pdfOnlyOptions } =
|
||||
options;
|
||||
|
||||
const pdfOptions = {
|
||||
scale,
|
||||
...pdfOnlyOptions
|
||||
};
|
||||
|
||||
const document = await pdf(pdfInput, pdfOptions);
|
||||
const outputImages = [];
|
||||
|
||||
if (
|
||||
page_numbers &&
|
||||
Array.isArray(page_numbers) &&
|
||||
page_numbers.length > 0
|
||||
) {
|
||||
for (const pageNum of page_numbers) {
|
||||
let image = await document.getPage(pageNum);
|
||||
|
||||
if (width || height) {
|
||||
const resizeOptions = {};
|
||||
if (width) resizeOptions.width = width;
|
||||
if (height) resizeOptions.height = height;
|
||||
image = await sharp(image).resize(resizeOptions).toBuffer();
|
||||
}
|
||||
|
||||
outputImages.push(image);
|
||||
}
|
||||
} else {
|
||||
for await (const image of document) {
|
||||
let processedImage = image;
|
||||
|
||||
if (width || height) {
|
||||
const resizeOptions = {};
|
||||
if (width) resizeOptions.width = width;
|
||||
if (height) resizeOptions.height = height;
|
||||
processedImage = await sharp(image)
|
||||
.resize(resizeOptions)
|
||||
.toBuffer();
|
||||
}
|
||||
|
||||
outputImages.push(processedImage);
|
||||
}
|
||||
}
|
||||
|
||||
return outputImages;
|
||||
} catch (error) {
|
||||
console.error('Error converting PDF to image:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,7 @@ import { dirname, join } from 'path';
|
||||
import { getObject, listObjects } from '../database/database.js';
|
||||
import { getModelByName } from '../utils.js';
|
||||
import { generatePDF } from './pdffactory.js';
|
||||
import { convertPDFToImage } from './pdfUtils.js';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
@ -595,6 +596,31 @@ export class TemplateManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template to image format for receipt printers
|
||||
* @param {string} id - The document template ID
|
||||
* @param {string} content - The template content
|
||||
* @param {Object} data - Data object to pass to the template
|
||||
* @param {Object} options - Image conversion options (e.g. width, height)
|
||||
* @returns {Promise<Object>} Object containing image buffers or error
|
||||
*/
|
||||
async renderJPG(id, content, data = {}, options = {}) {
|
||||
try {
|
||||
logger.debug('Rendering JPG for template:', id);
|
||||
|
||||
const pdfResult = await this.renderPDF(id, content, data, options);
|
||||
if (pdfResult.error != undefined) {
|
||||
return { error: pdfResult.error };
|
||||
}
|
||||
|
||||
const images = await convertPDFToImage(pdfResult.pdf, options);
|
||||
return { images };
|
||||
} catch (error) {
|
||||
logger.warn('Error whilst rendering JPG:', error.message);
|
||||
return { error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async listObjects(objectType, filter = {}, populate = []) {
|
||||
const model = getModelByName(objectType);
|
||||
if (model == undefined) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user