1/************************************************************************************************** 2 * EJDB2 Node.js native API binding. 3 * 4 * MIT License 5 * 6 * Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com> 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in all 16 * copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 * SOFTWARE. 25 *************************************************************************************************/ 26 27const fs = require('fs'); 28const request = require('request'); 29const progress = require('request-progress'); 30const Gauge = require('gauge'); 31const childProcess = require('child_process'); 32 33let platform = process.platform.toLowerCase(); 34if (platform.indexOf('win') === 0) { 35 platform = 'windows'; 36} 37 38/** 39 * @param {String} name 40 * @param {Array<String>} [args] 41 * @param {String} [cwd] 42 * @return {Promise<void>} 43 */ 44function runProcess(name, args, cwd) { 45 args = args || []; 46 console.log(`Spawn: ${name} ${args}`); 47 return awaitProcess(childProcess.spawn(name, args, { 48 stdio: ['ignore', process.stdout, process.stderr], 49 cwd 50 })); 51} 52 53function runProcessAndGetOutput(name, args, cwd) { 54 const res = []; 55 args = args || []; 56 console.log(`Spawn: ${name} ${args}`); 57 const proc = childProcess.spawn(name, args, { 58 stdio: ['ignore', 'pipe', 'pipe'], 59 cwd 60 }); 61 proc.stdout.on('data', (data) => res.push(data)); 62 proc.stderr.on('data', (data) => res.push(data)); 63 return awaitProcess(proc).then(() => { 64 return res.join(); 65 }); 66} 67 68/** 69 * @return {Promise<void>} 70 */ 71function awaitProcess(childProcess) { 72 return new Promise((resolve, reject) => { 73 childProcess.once('exit', (code) => { 74 if (code === 0) { 75 resolve(undefined); 76 } else { 77 reject(new Error('Exit with error code: ' + code)); 78 } 79 }); 80 childProcess.once('error', (err) => reject(err)); 81 }); 82} 83 84/** 85 * @param {String} url 86 * @param {String} dest 87 * @return {Promise<String>} 88 */ 89function download(url, dest, name) { 90 const gauge = new Gauge(); 91 return new Promise((resolve, reject) => { 92 let completed = false; 93 function handleError(err) { 94 if (!completed) { 95 gauge.hide(); 96 reject(err); 97 completed = true; 98 } 99 } 100 progress(request(url), { 101 throttle: 500, 102 delay: 0 103 }) 104 .on('progress', (state) => gauge.show(name || url, state.percent)) 105 .on('error', (err) => handleError(err)) 106 .on('end', () => { 107 if (!completed) { 108 gauge.hide(); 109 resolve(dest); 110 completed = true; 111 } 112 }) 113 .on('response', function (response) { 114 if (response.statusCode >= 400) { 115 handleError(`HTTP ${response.statusCode}: ${url}`); 116 } 117 }) 118 .pipe(fs.createWriteStream(dest)); 119 }); 120} 121 122module.exports = { 123 binariesDir: `${platform}-${process.arch}`, 124 download, 125 awaitProcess, 126 runProcess, 127 runProcessAndGetOutput 128}; 129