the-last-browser-launcher
Version:
Detect, launch and stop browsers
82 lines (67 loc) • 2.68 kB
JavaScript
'use strict'
const debug = require('debug')('airtap-system:launcher')
const EventEmitter = require('events').EventEmitter
const child = require('child_process')
const util = require('util')
const kManifest = Symbol('kManifest')
const kWindowsImage = Symbol('kWindowsImage')
/**
* Web browser instance
* @param {Object} options Configuration options
* @param {Array} options.args Array list of command line arguments
* @param {String} options.command Command used to start an instance's process
* @param {String} options.cwd Instance's current working directory
* @param {Boolean} options.detached Flag telling if the instance should be started in detached mode
* @param {Object} options.env Instance's environment variables
* @param {String} options.image Instance image (used to kill it on Windows)
*/
function Instance (manifest, options) {
EventEmitter.call(this)
this[kManifest] = manifest
this[kWindowsImage] = options.image
debug('spawn %o %o', options.command, options.args)
this.process = child.spawn(options.command, options.args, {
detached: options.detached,
env: options.env,
cwd: options.cwd
})
this.pid = this.process.pid
this.stdout = this.process.stdout
this.stderr = this.process.stderr
// on Windows Opera uses a launcher which is stopped immediately after opening the browser
// so it makes no sense to bind a listener, though we won't be noticed about crashes...
if (this[kManifest].name === 'opera' && process.platform === 'win32') {
return
}
// trigger "stop" event when the process exits
this.process.on('close', this.emit.bind(this, 'stop'))
}
util.inherits(Instance, EventEmitter)
/**
* Stop the instance
* @param {Function} callback Callback function called when the instance is stopped
*/
Instance.prototype.stop = function (callback) {
if (typeof callback === 'function') {
this.once('stop', callback)
}
if (process.platform === 'win32' && this[kWindowsImage]) {
// Opera case - it uses a launcher so we have to kill it somehow without a reference to the process
child.exec('taskkill /F /IM ' + this[kWindowsImage])
.on('close', this.emit.bind(this, 'stop'))
} else if (process.platform === 'win32' && this[kManifest].name === 'ie') {
// ie case on windows machine
child.exec('taskkill /F /IM iexplore.exe')
.on('close', this.emit.bind(this, 'stop'))
} else {
// every other scenario
this.process.kill()
}
}
Instance.prototype.unref = function () {
this.process.unref()
this.process.stdin.unref()
this.process.stdout.unref()
this.process.stderr.unref()
}
module.exports = Instance