@illgrenoble/visa-print-client
Version:
[](https://badge.fury.io/js/%40illgrenoble%2Fvisa-print-client)
251 lines (241 loc) • 10.6 kB
JavaScript
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