177 lines
5.5 KiB
JavaScript
177 lines
5.5 KiB
JavaScript
'use strict'
|
||
|
||
const os = require('os')
|
||
const url = require('url')
|
||
const path = require('path')
|
||
const cp = require('child_process')
|
||
const fs = require('fs-extra')
|
||
const request = require('request')
|
||
const extractZip = require('extract-zip')
|
||
|
||
const PHANTOM_VERSION = '2.1.1'
|
||
const DEFAULT_CDN = 'https://github.com/Medium/phantomjs/releases/download/v2.1.1'
|
||
const ARM_URL = 'https://github.com/fg2it/phantomjs-on-raspberry/raw/master/rpi-1-2-3/wheezy-jessie/v2.1.1/phantomjs'
|
||
const PLATFORM = os.platform()
|
||
const ARCH = os.arch()
|
||
|
||
const getDownloadUrl = () => {
|
||
let downloadUrl = DEFAULT_CDN + '/phantomjs-' + PHANTOM_VERSION + '-'
|
||
if (PLATFORM === 'linux' && ARCH === 'x64') {
|
||
downloadUrl += 'linux-x86_64.tar.bz2'
|
||
} else if (PLATFORM === 'linux' && ARCH == 'ia32') {
|
||
downloadUrl += 'linux-i686.tar.bz2'
|
||
} else if (PLATFORM === 'linux' && ARCH.search('arm') !== -1) {
|
||
downloadUrl = ARM_URL
|
||
} else if (PLATFORM === 'darwin') {
|
||
downloadUrl += 'macosx.zip'
|
||
} else if (PLATFORM === 'win32') {
|
||
downloadUrl += 'windows.zip'
|
||
} else {
|
||
return null
|
||
}
|
||
return downloadUrl
|
||
}
|
||
|
||
const downloadPhantomjs = (logger, downloadUrl, data_dir) => {
|
||
return new Promise((resolve, reject) => {
|
||
const file_name = downloadUrl.split('/').pop()
|
||
const downloaded_file = path.join(data_dir, file_name)
|
||
// actually downloads the file
|
||
const startDownload = (url, dest, cb) => {
|
||
const file = fs.createWriteStream(dest)
|
||
// download file
|
||
request(url)
|
||
.pipe(file)
|
||
.on('error', cb)
|
||
|
||
file.on('close', () => {
|
||
// close file & invoke callback
|
||
file.close()
|
||
cb()
|
||
})
|
||
}
|
||
startDownload(downloadUrl, downloaded_file, err => {
|
||
if (err) return reject(err)
|
||
resolve(downloaded_file)
|
||
})
|
||
})
|
||
}
|
||
|
||
const extractDownload = (logger, filePath) => {
|
||
return new Promise((resolve, reject) => {
|
||
var extractedPath = filePath + '-extract-' + Date.now()
|
||
var options = {cwd: extractedPath}
|
||
fs.mkdirsSync(extractedPath, '0777')
|
||
// Make double sure we have 0777 permissions; some operating systems
|
||
// default umask does not allow write by default.
|
||
fs.chmodSync(extractedPath, '0777')
|
||
if (filePath.substr(-4) === '.zip') {
|
||
logger.log('PHANTOMJS','Extracting zip contents')
|
||
extractZip(path.resolve(filePath), {dir: extractedPath}, err => {
|
||
if (err) {
|
||
reject(err)
|
||
} else {
|
||
resolve(extractedPath)
|
||
}
|
||
})
|
||
} else {
|
||
logger.log('PHANTOMJS', 'Extracting tar contents (via spawned process)')
|
||
cp.execFile('tar', ['jxf', path.resolve(filePath)], options, err => {
|
||
if (err) {
|
||
reject(err)
|
||
} else {
|
||
resolve(extractedPath)
|
||
}
|
||
})
|
||
}
|
||
})
|
||
}
|
||
|
||
const copyIntoPlace = (logger, extractedPath, archiveFile, targetPath) => {
|
||
return new Promise((resolve, reject) => {
|
||
logger.log('PHANTOMJS', `Removing ${archiveFile}`)
|
||
fs.removeSync(archiveFile)
|
||
const folders = fs.readdirSync(extractedPath)
|
||
const bin_dir = path.join(extractedPath, folders[0], 'bin')
|
||
const files = fs.readdirSync(path.join(extractedPath, folders[0], 'bin'))
|
||
let moved = false
|
||
for (let i = 0; i < files.length; i++) {
|
||
let file = path.join(bin_dir, files[i])
|
||
let filename = files[i]
|
||
let target = targetPath + path.sep + filename
|
||
logger.log('PHANTOMJS', `Copying extracted binary ${file} -> ${target}`)
|
||
fs.moveSync(file, target)
|
||
logger.log('PHANTOMJS', `Removing temporary download folder ${extractedPath}`)
|
||
fs.removeSync(extractedPath)
|
||
moved = target
|
||
}
|
||
|
||
if (moved !== false) {
|
||
resolve(moved)
|
||
} else {
|
||
reject()
|
||
}
|
||
})
|
||
}
|
||
|
||
const download = async (logger, phantom_bin, data_dir) => {
|
||
const download_url = getDownloadUrl()
|
||
let downloaded_file = ''
|
||
let extracted_folder = ''
|
||
let moved_file = ''
|
||
// error out if we couldn't find a suitable platform/arch combination
|
||
if (download_url === null) {
|
||
logger.log('ERROR',
|
||
`Unexpected platform or architecture: ${PLATFORM} / ${ARCH}\n` +
|
||
'It seems there is no binary available for your platform/architecture\n' +
|
||
`Try to install PhantomJS on your own & copy/link the executable to "${data_dir}"`)
|
||
return false
|
||
}
|
||
logger.log('PHANTOMJS', `Downloading from "${download_url}" to "${data_dir}/"`)
|
||
|
||
// download phantomjs
|
||
try {
|
||
downloaded_file = await downloadPhantomjs(logger, download_url, data_dir)
|
||
logger.log('PHANTOMJS', 'Download finished')
|
||
} catch (e) {
|
||
logger.log('ERROR', 'Error downloading PhantomJS - ' + e)
|
||
return false
|
||
}
|
||
|
||
// extract phantomjs (if needed)
|
||
// if it´s ARM, we´re done now
|
||
if (ARCH.search('arm') !== -1) return true
|
||
logger.log('PHANTOMJS', `Extracting PhantomJS binary: ${downloaded_file}`)
|
||
try {
|
||
extracted_folder = await extractDownload(logger, downloaded_file)
|
||
} catch (e) {
|
||
logger.log('ERROR', 'Error extracting PhantomJS - ' + e)
|
||
return false
|
||
}
|
||
|
||
logger.log('PHANTOMJS', 'Successfully extracted archive: "${extracted_folder}"')
|
||
|
||
// move Phantom executable
|
||
logger.log('PHANTOMJS', 'Moving executable to top level')
|
||
try {
|
||
moved_file = await copyIntoPlace(logger, extracted_folder, downloaded_file, data_dir)
|
||
} catch (e) {
|
||
logger.log('PHANTOMJS', 'Could not find extracted file')
|
||
return false
|
||
}
|
||
|
||
// make phantomjs executable
|
||
try {
|
||
fs.chmodSync(moved_file, '755')
|
||
} catch (e) {
|
||
logger.log('PHANTOMJS', 'Possible error with rights of downloaded Phantom binary')
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
module.exports = (logger) => {
|
||
return {
|
||
download: download.bind(this, logger)
|
||
}
|
||
} |