feat(smartpdf): add automatic port allocation and multi-instance support

This commit is contained in:
Juergen Kunz
2025-08-01 16:09:17 +00:00
parent f535eacd97
commit a4c3415838
7 changed files with 2102 additions and 2176 deletions

View File

@@ -7,10 +7,16 @@ import { execFile } from 'child_process';
declare const document: any;
export interface ISmartPdfOptions {
port?: number;
portRangeStart?: number;
portRangeEnd?: number;
}
export class SmartPdf {
// STATIC
public static async create() {
const smartpdfInstance = new SmartPdf();
public static async create(optionsArg?: ISmartPdfOptions) {
const smartpdfInstance = new SmartPdf(optionsArg);
return smartpdfInstance;
}
@@ -21,9 +27,15 @@ export class SmartPdf {
externalBrowserBool: boolean = false;
private _readyDeferred: plugins.smartpromise.Deferred<void>;
private _candidates: { [key: string]: PdfCandidate } = {};
private _options: ISmartPdfOptions;
constructor() {
constructor(optionsArg?: ISmartPdfOptions) {
this._readyDeferred = new plugins.smartpromise.Deferred();
this._options = {
portRangeStart: 20000,
portRangeEnd: 30000,
...optionsArg
};
}
async start(headlessBrowserArg?: plugins.smartpuppeteer.puppeteer.Browser) {
@@ -39,7 +51,37 @@ export class SmartPdf {
});
}
// setup server
// Find an available port BEFORE creating server
const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork();
if (this._options.port) {
// If a specific port is requested, check if it's available
const isPortAvailable = await smartnetworkInstance.isLocalPortUnused(this._options.port);
if (isPortAvailable) {
this.serverPort = this._options.port;
} else {
// Clean up browser if we created one
if (!this.externalBrowserBool && this.headlessBrowser) {
await this.headlessBrowser.close();
}
throw new Error(`Requested port ${this._options.port} is already in use`);
}
} else {
// Find a free port in the specified range
this.serverPort = await smartnetworkInstance.findFreePort(
this._options.portRangeStart,
this._options.portRangeEnd
);
if (!this.serverPort) {
// Clean up browser if we created one
if (!this.externalBrowserBool && this.headlessBrowser) {
await this.headlessBrowser.close();
}
throw new Error(`No free ports available in range ${this._options.portRangeStart}-${this._options.portRangeEnd}`);
}
}
// Now setup server after we know we have a valid port
const app = plugins.express();
app.get('/:pdfId', (req, res) => {
const wantedCandidate = this._candidates[req.params.pdfId];
@@ -51,10 +93,10 @@ export class SmartPdf {
res.send(wantedCandidate.htmlString);
});
this.htmlServerInstance = plugins.http.createServer(app);
const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork();
const portAvailable = smartnetworkInstance.isLocalPortUnused(3210);
this.htmlServerInstance.listen(3210, 'localhost');
this.htmlServerInstance.listen(this.serverPort, 'localhost');
this.htmlServerInstance.on('listening', () => {
console.log(`SmartPdf server listening on port ${this.serverPort}`);
this._readyDeferred.resolve();
done.resolve();
});
@@ -87,7 +129,7 @@ export class SmartPdf {
width: 794,
height: 1122,
});
const response = await page.goto(`http://localhost:3210/${pdfCandidate.pdfId}`, {
const response = await page.goto(`http://localhost:${this.serverPort}/${pdfCandidate.pdfId}`, {
waitUntil: 'networkidle2',
});
const headers = response.headers();