Some checks reported errors
farmcontrol/farmcontrol-server/pipeline/head Something is wrong with the build of this commit
201 lines
6.3 KiB
JavaScript
201 lines
6.3 KiB
JavaScript
// receiptinterface.js - Thermal receipt printer interface implementation
|
|
import log4js from "log4js";
|
|
import { loadConfig } from "../../config.js";
|
|
import { ThermalPrinter, PrinterTypes } from "node-thermal-printer";
|
|
import { convertPDFToImage } from "../../utils.js";
|
|
|
|
const config = loadConfig();
|
|
const logger = log4js.getLogger("Receipt Printer Interface");
|
|
logger.level = config.logLevel;
|
|
|
|
export default class ReceiptInterface {
|
|
constructor(documentPrinterClient) {
|
|
this.documentPrinterClient = documentPrinterClient;
|
|
this.host = documentPrinterClient.connection.host;
|
|
this.name = documentPrinterClient.documentPrinter.name;
|
|
this.port = documentPrinterClient.connection.port || 9100;
|
|
this.interface =
|
|
documentPrinterClient.connection.interface || "epsonReceipt";
|
|
this.protocol = documentPrinterClient.connection.protocol;
|
|
this.isConnected = false;
|
|
this.receiptPrinter = null;
|
|
this.retrieveStatusInterval = null;
|
|
this.images = new Map();
|
|
}
|
|
|
|
buildPrinterUrl() {
|
|
switch (this.protocol) {
|
|
case "tcp":
|
|
return `tcp://${this.host}:${this.port}`;
|
|
case "system":
|
|
return `printer:${this.host}`;
|
|
case "serial":
|
|
return this.host;
|
|
default:
|
|
logger.warn(`Unknown protocol ${this.protocol}, defaulting to tcp.`);
|
|
return `tcp://${this.host}:${this.port}`;
|
|
}
|
|
}
|
|
|
|
async connect() {
|
|
try {
|
|
// Determine printer type enum
|
|
let type;
|
|
switch (this.interface) {
|
|
case "epsonReceipt":
|
|
type = PrinterTypes.EPSON;
|
|
break;
|
|
case "starReceipt":
|
|
type = PrinterTypes.STAR;
|
|
break;
|
|
default:
|
|
type = PrinterTypes.EPSON;
|
|
logger.warn(
|
|
`Unknown interface ${this.interface}, defaulting to EPSON`
|
|
);
|
|
}
|
|
|
|
// Determine interface based on connection type
|
|
const interfaceStr = this.buildPrinterUrl();
|
|
|
|
logger.info(
|
|
`Connecting to receipt printer ${this.name} (${interfaceStr})`
|
|
);
|
|
|
|
// Initialize thermal printer
|
|
this.receiptPrinter = new ThermalPrinter({
|
|
type: type,
|
|
interface: interfaceStr,
|
|
options: {
|
|
timeout: 10000,
|
|
},
|
|
});
|
|
|
|
// Test connection
|
|
const isConnected = await this.receiptPrinter.isPrinterConnected();
|
|
if (!isConnected) {
|
|
logger.error("Printer is not connected or not reachable");
|
|
return { error: "Printer is not connected or not reachable." };
|
|
}
|
|
|
|
this.isConnected = true;
|
|
logger.info(`Successfully connected to receipt printer ${this.name}`);
|
|
return true;
|
|
} catch (error) {
|
|
logger.error(`Failed to connect to receipt printer ${this.name}:`, error);
|
|
this.isConnected = false;
|
|
return {
|
|
error: "Failed to connect to receipt printer. " + error.message,
|
|
};
|
|
}
|
|
}
|
|
|
|
async disconnect() {
|
|
logger.info(`Disconnecting from receipt printer ${this.name}`);
|
|
this.isConnected = false;
|
|
this.receiptPrinter = null;
|
|
return { success: true };
|
|
}
|
|
|
|
async initialize() {
|
|
logger.info(`Initializing receipt printer ${this.name}`);
|
|
// Thermal printers typically don't need special initialization
|
|
// but we can test the connection
|
|
if (this.receiptPrinter) {
|
|
try {
|
|
const isConnected = await this.receiptPrinter.isPrinterConnected();
|
|
if (!isConnected) {
|
|
logger.error(
|
|
`Printer not connected during initialization for receipt printer ${this.name}`
|
|
);
|
|
return { error: "Printer not connected during initialization" };
|
|
}
|
|
logger.info(`Receipt printer ${this.name} initialized successfully`);
|
|
} catch (error) {
|
|
logger.error(
|
|
`Failed to initialize receipt printer ${this.name}:`,
|
|
error
|
|
);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async print(jobId) {
|
|
logger.info(`Printing job ${jobId} to receipt printer ${this.name}`);
|
|
|
|
if (!this.isConnected || !this.receiptPrinter) {
|
|
throw new Error("Printer is not connected");
|
|
}
|
|
|
|
try {
|
|
// Clear the printer buffer to prevent previous print jobs from being included
|
|
this.receiptPrinter.clear();
|
|
|
|
const images = this.images.get(jobId);
|
|
if (!images || (Array.isArray(images) && images.length === 0)) {
|
|
throw new Error("Image not found");
|
|
}
|
|
|
|
// convertPDFToImage returns an array of buffers, so handle multiple pages
|
|
const imageArray = Array.isArray(images) ? images : [images];
|
|
|
|
for (const image of imageArray) {
|
|
// Ensure the image is a proper Buffer and create a fresh copy
|
|
// This prevents issues with pngjs reading from consumed streams
|
|
// pdf-to-img returns PNG buffers, but we create a copy to avoid any stream issues
|
|
const imageBuffer = Buffer.isBuffer(image)
|
|
? Buffer.from(image) // Create a fresh copy
|
|
: Buffer.from(image); // Convert if needed
|
|
this.receiptPrinter.printImageBuffer(imageBuffer);
|
|
this.receiptPrinter.cut();
|
|
}
|
|
|
|
// Execute the print job
|
|
await this.receiptPrinter.execute({ waitForResponse: true });
|
|
|
|
logger.info(
|
|
`Successfully printed job ${jobId} to receipt printer ${this.name}`
|
|
);
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
logger.error(
|
|
`Failed to print job ${jobId} to receipt printer ${this.name}:`,
|
|
error
|
|
);
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
async deploy(documentJob, pdf) {
|
|
logger.info(
|
|
`Deploying job ${documentJob._id} to receipt printer ${this.name}`
|
|
);
|
|
|
|
const images = await convertPDFToImage(pdf, { width: 512 });
|
|
// Store the array of image buffers
|
|
this.images.set(documentJob._id, images);
|
|
return { success: true };
|
|
}
|
|
|
|
async retrieveStatus() {
|
|
logger.debug(`Getting status of receipt printer ${this.name}`);
|
|
if (this.isOnline == false) {
|
|
logger.error("Printer is not connected or not reachable");
|
|
return { error: "Printer is not connected or not reachable." };
|
|
}
|
|
try {
|
|
const status = await this.receiptPrinter.raw(
|
|
Buffer.from([0x10, 0x04, 0x04])
|
|
);
|
|
logger.info(`Printer status: ${status}`);
|
|
} catch (error) {
|
|
logger.error(`Failed to execute printer status:`, error);
|
|
}
|
|
|
|
logger.debug(`Receipt printer ${this.name} is connected.`);
|
|
return true;
|
|
}
|
|
}
|