geckodriver
Version:
Mozilla's Geckodriver for Node.js
85 lines • 3.53 kB
JavaScript
import os from 'node:os';
import path from 'node:path';
import util from 'node:util';
import stream from 'node:stream';
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import zlib from 'node:zlib';
import { Readable } from 'node:stream';
import tar from 'tar-fs';
import fetch from 'node-fetch';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { HttpProxyAgent } from 'http-proxy-agent';
import unzipper from 'unzipper';
import { BINARY_FILE, MOZ_CENTRAL_CARGO_TOML, log } from './constants.js';
import { hasAccess, getDownloadUrl } from './utils.js';
const streamPipeline = util.promisify(stream.pipeline);
const fetchOpts = {};
if (process.env.HTTPS_PROXY) {
fetchOpts.agent = new HttpsProxyAgent(process.env.HTTPS_PROXY);
}
else if (process.env.HTTP_PROXY) {
fetchOpts.agent = new HttpProxyAgent(process.env.HTTP_PROXY);
}
export async function download(geckodriverVersion = process.env.GECKODRIVER_VERSION, cacheDir = process.env.GECKODRIVER_CACHE_DIR || os.tmpdir()) {
const binaryFilePath = path.resolve(cacheDir, BINARY_FILE);
if (await hasAccess(binaryFilePath)) {
return binaryFilePath;
}
/**
* get latest version of Geckodriver
*/
if (!geckodriverVersion) {
const res = await fetch(MOZ_CENTRAL_CARGO_TOML, fetchOpts);
const toml = await res.text();
const version = toml.split('\n').find((l) => l.startsWith('version = '));
if (!version) {
throw new Error(`Couldn't find version property in Cargo.toml file: ${toml}`);
}
geckodriverVersion = version.split(' = ').pop().slice(1, -1);
log.info(`Detected Geckodriver v${geckodriverVersion} to be latest`);
}
const url = getDownloadUrl(geckodriverVersion);
log.info(`Downloading Geckodriver from ${url}`);
const res = await fetch(url, fetchOpts);
if (res.status !== 200) {
throw new Error(`Failed to download binary (statusCode ${res.status}): ${res.statusText}`);
}
await fsp.mkdir(cacheDir, { recursive: true });
await (url.endsWith('.zip')
? downloadZip(res.body, cacheDir)
: streamPipeline(res.body, zlib.createGunzip(), tar.extract(cacheDir)));
await fsp.chmod(binaryFilePath, '755');
return binaryFilePath;
}
function downloadZip(body, cacheDir) {
const stream = Readable.from(body).pipe(unzipper.Parse());
const promiseChain = [
new Promise((resolve, reject) => {
stream.on('close', () => resolve());
stream.on('error', () => reject());
})
];
stream.on('entry', async (entry) => {
const unzippedFilePath = path.join(cacheDir, entry.path);
if (entry.type === 'Directory') {
return;
}
if (!await hasAccess(path.dirname(unzippedFilePath))) {
await fsp.mkdir(path.dirname(unzippedFilePath), { recursive: true });
}
const execStream = entry.pipe(fs.createWriteStream(unzippedFilePath));
promiseChain.push(new Promise((resolve, reject) => {
execStream.on('close', () => resolve(unzippedFilePath));
execStream.on('error', reject);
}));
});
return Promise.all(promiseChain);
}
/**
* download on install
*/
if (process.argv[1] && process.argv[1].endsWith('/dist/install.js') && Boolean(process.env.GECKODRIVER_AUTO_INSTALL || '1')) {
await download().then(() => log.info('Success!'), (err) => log.error(`Failed to install Geckodriver: ${err.stack}`));
}
//# sourceMappingURL=install.js.map