UNPKG

@illgrenoble/visa-print-client

Version:

[![npm version](https://badge.fury.io/js/%40illgrenoble%2Fvisa-print-client.svg)](https://badge.fury.io/js/%40illgrenoble%2Fvisa-print-client)

251 lines (241 loc) 10.6 kB
import * as i0 from '@angular/core'; import { Injectable, NgModule } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import io from 'socket.io-client'; class PrintEvent { constructor(data) { Object.assign(this, data); } } class PrintJobChunkEvent { constructor(data) { Object.assign(this, data); } } class PrintJobAvailableEvent { constructor(data) { Object.assign(this, data); } } class ErrorEvent { constructor(data) { Object.assign(this, data); } } class VisaPrintService { constructor() { this._connections = []; this._pdfDidOpen = false; } static { this._connectionCounter = 1; } connect(data, connectionOptions) { connectionOptions = connectionOptions || {}; const socketOptions = { transports: ['websocket'], timeout: 1000, reconnection: true, reconnectionDelayMax: 10000, ...connectionOptions }; if (data.path) { socketOptions.path = data.path; } if (data.token) { socketOptions.auth = { token: data.token }; socketOptions.query = { token: data.token }; } const connectionId = `print-connection-${VisaPrintService._connectionCounter++} `; const location = window.location; const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; const hostname = location.hostname; const port = location.port ? `:${location.port}` : ''; const host = data.host ? `${data.host}` : `${protocol}//${hostname}${port}`; const socket = io(`${host}`, socketOptions); const printEvents$ = new BehaviorSubject(new PrintEvent({ type: 'CONNECTING', connectionId })); const connection = { id: connectionId, event$: printEvents$, socket: socket, jobs: new Map(), printables: [], }; this._connections.push(connection); socket.on('connect', () => { printEvents$.next(new PrintEvent({ type: 'CONNECTED', connectionId })); }); socket.on('print_job_handled', (jobId) => { connection.printables = connection.printables.filter(printable => printable.jobId !== jobId); printEvents$.next(new PrintEvent({ type: 'PRINT_JOB_HANDLED', connectionId, jobId })); }); socket.on('connect_error', (error) => { printEvents$.next(new PrintEvent({ type: 'ERROR', connectionId, data: new ErrorEvent({ type: 'CONNECTION_ERROR', message: error.message }) })); }); socket.on('disconnect', () => { printEvents$.next(new PrintEvent({ type: 'DISCONNECTED', connectionId })); }); socket.on('error', (error) => { printEvents$.next(new PrintEvent({ type: 'ERROR', connectionId, data: new ErrorEvent({ type: 'ERROR', message: error.message }) })); }); socket.on('exception', (e) => { printEvents$.next(new PrintEvent({ type: 'ERROR', connectionId, data: new ErrorEvent({ type: 'EXCEPTION', message: e.message }) })); }); socket.on('print_job_start', (jobId) => { printEvents$.next(new PrintEvent({ type: 'PRINT_JOB_TRANSFER_STARTED', connectionId, jobId })); }); socket.on('print_job_end', (jobId) => { printEvents$.next(new PrintEvent({ type: 'PRINT_JOB_TRANSFER_TERMINATED', connectionId, jobId })); }); socket.on('print_job_data', (printJob, ack) => { const { jobId, chunkId, chunkCount, chunkLength, data } = printJob; if (chunkLength !== data.length) { console.error(`printer job data of chunk ${chunkId}/${chunkCount} for job ${jobId} ${printJob.fileName} has incorrect length`); printEvents$.next(new PrintEvent({ type: 'ERROR', connectionId, data: new ErrorEvent({ type: 'ERROR', message: 'Incorrect data length in chunk' }) })); ack(false); return; } ack(true); printEvents$.next(new PrintEvent({ type: 'PRINT_JOB_CHUNK_RECEIVED', connectionId, jobId, data: new PrintJobChunkEvent({ jobId, chunkId, chunkCount, chunkLength }) })); this.handlePrintJob(connection, printJob); }); return printEvents$; } disconnect(connectionId) { const connection = this._connections.find(connection => connection.id === connectionId); if (connection) { connection.socket.disconnect(); } this._connections = this._connections.filter(connection => connection.id !== connectionId); } enablePrinting(connectionId) { const connection = this._connections.find(connection => connection.id === connectionId); if (connection) { connection.socket.emit('enable_print', null, (data) => { connection.event$.next(new PrintEvent({ type: 'PRINT_ENABLED', connectionId })); }); } } disablePrinting(connectionId) { const connection = this._connections.find(connection => connection.id === connectionId); if (connection) { connection.socket.emit('disable_print', null, (data) => { connection.event$.next(new PrintEvent({ type: 'PRINT_DISABLED', connectionId })); }); } } openPrintable(connectionId, jobId) { const connection = this._connections.find(connection => connection.id === connectionId); if (connection) { const printable = connection.printables.find(printable => printable.jobId === jobId); if (printable) { connection.socket.emit('print_job_handled', printable.jobId); connection.printables = connection.printables.filter(printable => printable.jobId !== jobId); this.openPDF(printable.data, connection, jobId); } } } initialiseReceiver() { if (!this._iframe) { this._iframe = document.createElement('iframe'); this._iframe.style.display = 'none'; document.body.appendChild(this._iframe); this._iframe.onload = () => { URL.revokeObjectURL(this._pdfUrl); this._iframe.focus(); try { this._iframe.contentWindow?.print(); this._pdfDidOpen = true; } catch (error) { } }; } } handlePrintJob(connection, printJob) { const { jobId, chunkId, chunkCount } = printJob; if (!connection.jobs.has(jobId)) { connection.jobs.set(jobId, []); } connection.jobs.get(jobId)?.push(printJob); if (chunkId === chunkCount) { this.processJob(connection, printJob); } } processJob(connection, printJob) { const { jobId, chunkCount, fileLength, fileName } = printJob; const chunks = connection.jobs.get(jobId); if (chunks) { // Remove from jobs connection.jobs.delete(jobId); // Concatenate all the data if (chunks.length > 0 && chunks.length === chunkCount) { const base64 = chunks.reduce((acc, chunk) => { return acc + chunk.data; }, ''); const data = atob(base64); if (data.length === fileLength) { connection.printables.push({ jobId, data }); connection.event$.next(new PrintEvent({ type: 'PRINT_JOB_AVAILABLE', connectionId: connection.id, data: new PrintJobAvailableEvent({ jobId, fileLength, fileName }) })); } else { connection.event$.next(new PrintEvent({ type: 'ERROR', connectionId: connection.id, data: new ErrorEvent({ type: 'ERROR', message: 'Processes print data has inconsistent length' }) })); } } } } openPDF(data, connection, jobId) { // Convert to binary data const bytes = new Uint8Array(data.length); for (let i = 0; i < data.length; i++) { bytes[i] = data.charCodeAt(i); } const blob = new Blob([bytes], { type: 'application/pdf' }); this._pdfUrl = URL.createObjectURL(blob); this.initialiseReceiver(); // Set the pdf in the iframe this._pdfDidOpen = false; this._iframe.src = this._pdfUrl; setTimeout(() => { if (this._pdfDidOpen === false) { connection.event$.next(new PrintEvent({ type: 'PRINT_DIALOG_FAILED', connectionId: connection.id, jobId })); } }, 200); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.7", ngImport: i0, type: VisaPrintService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.7", ngImport: i0, type: VisaPrintService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.7", ngImport: i0, type: VisaPrintService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); class VisaPrintModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.7", ngImport: i0, type: VisaPrintModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.7", ngImport: i0, type: VisaPrintModule }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.7", ngImport: i0, type: VisaPrintModule, providers: [ VisaPrintService, ] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.7", ngImport: i0, type: VisaPrintModule, decorators: [{ type: NgModule, args: [{ declarations: [], imports: [], exports: [], providers: [ VisaPrintService, ] }] }] }); /* * Public API Surface of lib */ /** * Generated bundle index. Do not edit. */ export { ErrorEvent, PrintEvent, PrintJobAvailableEvent, PrintJobChunkEvent, VisaPrintModule, VisaPrintService }; //# sourceMappingURL=illgrenoble-visa-print-client.mjs.map