qztrayjsclass
Version:
QZTray JS Class wrapper for easy implementation of the QZ-Tray.
320 lines (300 loc) • 11.6 kB
JavaScript
/* eslint-disable no-underscore-dangle */
import QzTray from 'qz-tray';
import sha256 from 'js-sha256';
import { logError, logInfo, required } from './helpers';
/**
* @version 1.0
* @overview QZTrayPrinter
* QZ Tray class wrapper
* @class QZTrayPrinter
* @requires Axios
* @requires QzTray
* @requires sha256
*/
/**
* @namespace QZTrayPrinter
*/
/**
* @typedef {Object} QZTrayPrinter_PrinterConfig
* @property {string}.colorType='color' Valid values <code>[color | grayscale | blackwhite </code>
* @property {number} copies=1 Number of copies to be printed.
* @property {number|Array<number>} density=72 Pixel density (DPI, DPMM, or DPCM depending on <code>units </code>). If provided as an array, uses the first supported density found (or the first entry if none found).
* @property {boolean} duplex=false Double sided printing
* @property {number} fallbackDensity=null Value used when default density value cannot be read, or in cases where reported as "Normal" by the driver, (in DPI, DPMM, or DPCM depending on <code>units </code>).
* @property {string} interpolation='bicubic' Valid values <code>[bicubic | bilinear | nearest-neighbor </code>. Controls how images are handled when resized.
* @property {string} jobName=null Name to display in print queue.
* @property {boolean} legacy=false If legacy style printing should be used.
* @property {Object|number} margins=0 If just a number is provided, it is used as the margin for all sides.
* @property {number} margins.top=0]
* @property {number} margins.right=0]
* @property {number} margins.bottom=0]
* @property {number} margins.left=0]
* @property {string} orientation=null Valid values <code>[portrait | landscape | reverse-landscape </code>
* @property {number} paperThickness=null]
* @property {string} printerTray=null //TODO - string?
* @property {boolean} rasterize=true Whether documents should be rasterized before printing. Forced TRUE if <code>density </code> is specified.
* @property {number} rotation=0 Image rotation in degrees.
* @property {boolean} scaleContent=true Scales print content to page size, keeping ratio.
* @property {Object} size=null Paper size.
* @property {number} size.width=null Page width.
* @property {number} size.height=null Page height.
* @property {string} units='in' Page units, applies to paper size, margins, and density. Valid value <code>[in | cm | mm </code>
* @property {boolean} altPrinting=false Print the specified file using CUPS command line arguments. Has no effect on Windows.
* @property {string} encoding=null Character set
* @property {string} endOfDoc=null]
* @property {number} perSpool=1 Number of pages per spool.
*/
/**
* @typedef {Object} QZTrayPrinter_PageConfig
* @property {string} language Required with <code>[raw]</code> type <code>[image]</code> format. Printer language.
* @property {number} x Optional with <code>[raw]</code> type <code>[image]</code> format. The X position of the image.
* @property {number} y Optional with <code>[raw]</code> type <code>[image]</code> format. The Y position of the image.
* @property {string|number} dotDensity Optional with <code>[raw]</code> type <code>[image]</code> format.
* @property {number} [data.precision=128 Optional with <code>[raw]</code> type <code>[image]</code> format. Bit precision of the ribbons.
* @property {boolean|string|Array<Array<number>>} overlay=false Optional with <code>[raw]</code> type <code>[image]</code> format.
* Boolean sets entire layer, string sets mask image, Array sets array of rectangles in format <code>[x1,y1,x2,y2]</code>.
* @property {string} xmlTag Required with <code>[xml]</code> format. Tag name containing base64 formatted data.
* @property {number} pageWidth Optional with <code>[html]</code> type printing. Width of the web page to render. Defaults to paper width.
* @property {number} pageHeight Optional with <code>[html]</code> type printing. Height of the web page to render. Defaults to adjusted web page height.
* @property {boolean} [signature Pre-signed signature of JSON string containing <code>call</code>, <code>params</code>, and <code>timestamp</code>.
* @property {number} [signingTimestamp Required with <code>signature</code>. Timestamp used with pre-signed content.
*/
class QZTrayPrinter {
/**
* @constructor
* @param {QZTrayPrinterConstructor} parameters
*/
/**
* @typedef {object} QZTrayPrinterConstructor
* @property {string} certificateUrl - QZ Tray Certificate URL
* @property {string} signUrl - QZ Tray Certificate URL
* @property {QZTrayPrinter_Printer} printer - Printer Name
*/
/**
* @typedef {string|object} QZTrayPrinter_Printer printer Name of printer.
* Use object type to specify printing to file or host.
* @property {string} name Name of printer to send printing.
* @property {string} file Name of file to send printing.
* @property {string} host IP address or host name to send printing.
* @property {string} port Port used by <printer.host>.
*/
constructor(parameters) {
this.__qz = QzTray;
this.__qz.api.setPromiseType(resolver => new Promise(resolver));
this.__qz.api.setWebSocketType(WebSocket);
this.__qz.api.setSha256Type(data => sha256(data));
this.certificateUrl = required('certificateUrl', parameters.certificateUrl);
this.rawCertificate = parameters.rawCertificate || '';
this.signUrl = required('signUrl', parameters.signUrl);
this.printer = required('printer', parameters.printer);
}
/**
* Start QZ Tray Printer
* @namespace QZTrayPrinter.start
* @returns {Promise<void>}
*/
async start() {
try {
if (this.rawCertificate) {
this.__qz.security.setCertificatePromise((resolve, reject) => resolve(this.rawCertificate));
} else {
this.__qz.security.setCertificatePromise((resolve, reject) => this.__fetchCertificate().then(resolve, reject));
}
this.__qz.security.setSignaturePromise(toSign => (resolve, reject) => this.__singCertificate(toSign).then(resolve, reject));
if (!this.__qz.websocket.isActive()) await this.__printerConnect();
} catch (error) {
await QZTrayPrinter.__classError(error);
}
}
/**
* Close QZ Tray Printer
* @namespace QZTrayPrinter.close
* @returns {Promise<void>}
*/
async close() {
try {
this.__qz.websocket.disconnect();
} catch (error) {
await QZTrayPrinter.__classError(error);
}
}
async __fetchCertificate() {
try {
const certificateFetch = await fetch(this.certificateUrl, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'text/plain',
},
});
const certificateText = await certificateFetch.text();
return Promise.resolve(certificateText);
} catch (error) {
return Promise.reject(error);
}
}
async __singCertificate(toSign) {
try {
const signedCertificateRequest = await fetch(this.signUrl, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ request: toSign }),
});
const signedCertificate = await signedCertificateRequest.json();
return Promise.resolve(signedCertificate);
} catch (error) {
return Promise.reject(error);
}
}
/**
* @typedef {object} QZTrayPrinterConnectOptions
* @property {number} retries
* @property {number} delay
*/
/**
* @private
* Connect to the printer
* @param {QZTrayPrinterConnectOptions} options - Printer connection options
* @param {boolean} retry - It's a retry call
* @returns {Promise<void>}
* @private
*/
async __printerConnect(options = {}, retry = false) {
try {
if (!this.__qz.websocket.isActive()) {
if (retry) window.location.assign('qz:launch');
await this.__qz.websocket.connect(options);
}
} catch (error) {
if (!retry) {
await this.__printerConnect({
retries: 2,
delay: 1,
}, true);
} else {
await QZTrayPrinter.__classError(error);
}
}
}
/**
* HTML Print
* @namespace QZTrayPrinter.htmlPrint
* @param {string} pageUrl
* @param {string} format
* @param {QZTrayPrinter_PageConfig} pageOptions
* @param {QZTrayPrinter_PrinterConfig} printerOptions
* @returns {Promise<void>}
*/
async htmlPrint({
pageUrl,
pageOptions,
printerOptions,
format,
}) {
try {
const printerTrayOptions = printerOptions || {};
const config = this.__qz.configs.create(this.printer, printerTrayOptions);
const data = {
type: 'html',
format: format || 'file',
data: pageUrl,
options: pageOptions || {},
};
await this.__qz.print(config, [data]);
} catch (error) {
await QZTrayPrinter.__classError(error);
}
}
/**
* PDF Print
* @namespace QZTrayPrinter.pdfPrint
* @param {string} pdfData
* @param {boolean} isBase64
* @param {QZTrayPrinter_PageConfig} pageOptions
* @param {QZTrayPrinter_PrinterConfig} printerOptions
* @returns {Promise<void>}
*/
async pdfPrint({
pdfData,
isBase64,
pageOptions,
printerOptions,
}) {
try {
const printerTrayOptions = printerOptions || {};
const config = this.__qz.configs.create(this.printer, printerTrayOptions);
const data = [
{
type: 'pdf',
data: pdfData,
options: pageOptions || {},
},
];
if (isBase64) data.format = 'base64';
await this.__qz.print(config, data);
} catch (error) {
await QZTrayPrinter.__classError(error);
}
}
/**
* Image Print
* @namespace QZTrayPrinter.imagePrint
* @param {string} imgData
* @param {boolean} isBase64
* @param {QZTrayPrinter_PageConfig} pageOptions
* @param {QZTrayPrinter_PrinterConfig} printerOptions
* @returns {Promise<void>}
*/
async imagePrint({
imgData,
isBase64,
pageOptions,
printerOptions,
}) {
try {
const printerTrayOptions = printerOptions || {};
const config = this.__qz.configs.create(this.printer, printerTrayOptions);
const data = [
{
type: 'image',
data: imgData,
options: pageOptions || {},
},
];
if (isBase64) data.format = 'base64';
await this.__qz.print(config, [data]);
} catch (error) {
await QZTrayPrinter.__classError(error);
}
}
/**
* Raw Print
* @namespace QZTrayPrinter.rawPrint
* @param {array} rawData
* @param {QZTrayPrinter_PageConfig} pageOptions
* @param {QZTrayPrinter_PrinterConfig} printerOptions
* @returns {Promise<void>}
*/
async rawPrint({
rawData,
pageOptions,
printerOptions,
}) {
try {
const printerTrayOptions = printerOptions || {};
const config = this.__qz.configs.create(this.printer, printerTrayOptions);
await this.__qz.print(config, rawData);
} catch (error) {
await QZTrayPrinter.__classError(error);
}
}
static async __classError(error) {
logError(error);
}
}
export default QZTrayPrinter;