browser-launcher
Version:
detect and launch browser versions, headlessly or otherwise
159 lines (144 loc) • 5.49 kB
JavaScript
var headless = require('headless');
var fs = require('fs');
var path = require('path');
var spawn = require('child_process').spawn;
var argue = {};
argue.firefox = function (br, uri, opts, cb) {
var prefs = '';
opts.options = opts.options || [];
if (opts.proxy) {
var m = /^(?:http:\/\/)?([^:\/]+)(?::(\d+))?/.exec(opts.proxy);
var host = JSON.stringify(m[1]);
var port = m[2] || 80;
prefs += [
'"network.proxy.http", ' + host,
'"network.proxy.http_port", ' + port,
'"network.proxy.type", 1',
'"browser.cache.disk.capacity", 0',
'"browser.cache.disk.smart_size.enabled", false',
'"browser.cache.disk.smart_size.first_run", false',
'"browser.sessionstore.resume_from_crash", false',
'"browser.startup.page", 0',
'"network.proxy.no_proxies_on", '
+ JSON.stringify(opts.noProxy || '')
,
].map(function (x) { return 'user_pref(' + x + ');\n' }).join('');
}
prefs += 'user_pref("browser.shell.checkDefaultBrowser", false);\n';
var file = path.join(br.profile.file, 'user.js');
fs.writeFile(file, prefs, function (err) {
if (err) cb(err)
else cb(null, opts.options.concat([
'--no-remote',
'-P', br.profile.name,
uri,
]))
});
};
argue.ie = function(br, uri, opts, cb) {
cb(null, [uri]);
};
argue.safari = function(br, uri, opts, cb) {
cb(null, [uri]);
};
argue.chrome = function (br, uri, opts, cb) {
opts.options = opts.options || [];
cb(null, opts.options.concat([
opts.proxy ? '--proxy-server=' + opts.proxy : null,
br.profile ? '--user-data-dir=' + br.profile : null,
'--disable-restore-session-state',
'--no-default-browser-check',
'--start-maximized',
'--disable-default-apps',
'--disable-sync',
'--enable-fixed-layout',
'--no-first-run',
'--noerrdialogs ',
uri,
]).filter(Boolean));
};
module.exports = function (config, name, version) {
var m = selectMatch(config, name, version);
if (!m) return;
return function (uri, opts, cb) {
if (opts.headless && !m.headless) {
headless(function (err, proc, display) {
run({ DISPLAY : ':' + display });
});
}
else run({})
function run (env_) {
var env = {},
cwd = process.cwd();
Object.keys(process.env).forEach(function (key) {
env[key] = process.env[key];
});
Object.keys(env_).forEach(function (key) {
env[key] = env_[key];
});
argue[m.type](m, uri, opts, function (err, args) {
if (err) return cb(err);
if (opts.noProxy && env.no_proxy === undefined) {
env.no_proxy = opts.noProxy;
}
if (opts.proxy && env.http_proxy === undefined) {
env.http_proxy = opts.proxy;
}
if (opts.proxy && env.HTTP_PROXY === undefined) {
env.HTTP_PROXY = opts.proxy;
}
switch (process.platform) {
case 'win32':
m.command = m.command.replace(/"/g, ''); //Ensure all the quotes are removed
cwd = require('path').dirname(m.command); //Change directory to the app's base (Chrome)
break;
case 'darwin':
if (m.name !== 'firefox') { //Use the bin path under the hood
/*
This creates a command line structure like this:
open --wait-apps --new --fresh -a /Path/To/Executable <url> --args <rest of app args>
*/
args.unshift('--args');
args.unshift(args.pop());
args.unshift(m.command);
args.unshift('-a');
args.unshift('--fresh');
args.unshift('--new');
args.unshift('--wait-apps');
m.command = 'open';
}
break;
}
cb(null, spawn(m.command, args, { env : env, cwd: cwd }));
});
}
};
};
function selectMatch (config, name, version) {
var order = (config.preference || []).concat(Object.keys(config.browsers));
for (var i = 0; i < order.length; i++) {
var bs = config.browsers[order[i]];
var matching = bs
.filter(function (b) {
return b.name === name
&& matches(b.version, version)
;
})
.sort(function (a, b) {
return b.version - a.version;
})
;
if (matching.length) return matching[0];
}
}
function matches (version, pattern) {
if (pattern === undefined || pattern === '*') return true;
// todo: real semvers
var vs = version.split('.');
var ps = pattern.split('.');
for (var i = 0; i < ps.length; i++) {
if (ps[i] === 'x' || ps[i] === '*') continue;
if (ps[i] !== vs[i]) return false;
}
return true;
}