import {NPAS_Options} from "../index"; import {Utils} from "./utils"; export class PHPServer { defaultOptions: any = {}; options: any; args: string[] = []; events: any = require('events'); emitter: any = new this.events(); php: any = {}; utils: Utils = new Utils(); constructor(options: NPAS_Options, public workerId: number, public workerPid: number, instanceNr: number) { const {spawn} = require('child_process'); this.options = Object.assign({}, this.defaultOptions, options); this.php = spawn(this.options.bin, this.prepareArguments(), { stdio: ['pipe', 'pipe', 'pipe'] }); /** * Assign Worker ID to php instance * @type {number} */ this.php.workerId = workerId; this.php.workerPid = options.port; this.php.instanceNr = instanceNr; /** * Waiting for the server ... */ this.phpCheck(); for (let item in this.php) { if (this.php.hasOwnProperty(item)) { this.emitter[item] = typeof this.php[item] === 'function' ? this.php[item].bind(this) : this.php[item]; } } } /** * Listener * @param event * @param callback */ on(event: string, callback: (...input: any[]) => void): this { this.emitter.on(event, callback); return this; } /** * Format the parameters used for the PHP server and returns an array of arguments * @returns {string[] | number[]} */ prepareArguments(): string[] | number[] { /** * Add INI values */ if (Object.keys(this.options.ini_set).length) { for (let ini_val in this.options.ini_set) { this.args.push(`-d`); this.args.push(`${ini_val}="${this.options.ini_set[ini_val]}"`); } } /** * Add custom ini config */ if (typeof this.options.ini_config && this.options.ini_config.substr(-4,4) === '.ini') { this.args.push(`-c`); this.args.push(this.options.ini_config); } /** * Add server argument */ this.args.push('-S'); /** * Add server bind address */ this.args.push(this.getBindAddress()); /** * Add document root */ if (this.options.root.length) { this.args.push('-t'); this.args.push(this.options.root.replace(/[/\\]+/g, "/").replace(/[\/\\]$/, "")); } /** * Add router file */ if (this.options.router.length) { this.args.push(Utils.root("..", "router", "router.wrapper.php")); } return this.args; } /** * Retrieve a valid format of host and port * @returns {string} */ private getBindAddress(): string { if (this.options.host.length === 0) { this.options.host = this.defaultOptions.host; } if (this.options.port) { if ((this.options.port < 1 || this.options.port > 65535) || isNaN(+this.options.port)) { console.log('Invalid port!'); process.exit(1); } } else { this.options.port = 0; } //return this.options.host + ( this.options.port ? ':' + this.options.port : ''); return '127.0.0.1' + (this.options.port ? ':' + this.options.port : ''); } /** * Check if the PHP server has started and emit 'connect' Event * @returns {void} */ phpCheck(): void { let net = require('net'); let netClient = net.createConnection({ port: +this.options.port }); netClient.on('error', (err: any) => { let errors = ['ECONNREFUSED', 'ECONNRESET']; if (errors.indexOf(err) === -1) { netClient.unref(); netClient.destroy(); return this.phpCheck(); } }); netClient.on('connect', () => { /** * PHP Server is available for use */ this.emitter.emit('connect', this.php); }).end(); } }