Curl install binary to users path from nodejs - node.js

Hello fellow nerds and nerdettes,
I just started building a little app that uses an external command line interface. The app first checks if the binary is installed in the users path and if not offers to install it for them. The external cli bin is the digitalocean cli and requires to curl, pipe to tar, and then move the bin into the users path. I have built the check if installed functionality and have been reading the child-process api but have been having a hard time figuring out how to console out the status of the curl command. My current incantation shows no console output. My question is this. How do i pipe the output of cURL to the console to confirm its working? How might i go about testing success then moving on?
Thanks y'all
const exec = require('child_process').exec
const curlScriptOSX = 'curl -L https://github.com/digitalocean/doctl/releases/download/v1.6.0/doctl-1.6.0-darwin-10.6-amd64.tar.gz | tar xz'
exec(curlScriptOSX, function(error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if(error !== null) {
console.log('exec error: ' + error);
}
})
UPDATE: i am looking at the request library as well. is it possible to
request(url).pipe(fs.createWriteStream('binary.tar.gz')).then(exec(extracting)).catch(err => console.error(err))
i wonder... ima try this now

Using the request library:
const fs = require('fs')
const os = require('os')
const request = require('request')
const url = 'https://github.com/digitalocean/doctl/releases/download/v1.6.0/doctl-1.6.0-darwin-10.6-amd64.tar.gz'
platform = os.platform()
function getInstallerFile (url) {
console.log("Getting tar")
// Variable to save downloading progress
var received_bytes = 0;
var total_bytes = 0;
const output = fs.createWriteStream('doctl.tar.gz')
request
.get(url)
.on('error', function(err) {
console.log(err);
})
.on('response', function(data) {
total_bytes = parseInt(data.headers['content-length']);
})
.on('data', function(chunk) {
received_bytes += chunk.length;
showDownloadingProgress(received_bytes, total_bytes);
})
.pipe(output);
};
function showDownloadingProgress(received, total) {
var percentage = ((received * 100) / total).toFixed(2);
process.stdout.write((platform == 'win32') ? "\033[0G": "\r");
process.stdout.write(percentage + "% | " + received + " bytes of " + total + " bytes.");
}
getInstallerFile(url)

Related

Too many connections cause node crash

My node program is crashed without any log.
I run the program below with node index.js.
const childProcess = require('child_process')
const util = require('util');
const exec = util.promisify(childProcess.exec);
console.time('total');
console.log("start");
const urlList = Array(500).fill("https://google.com");
const pList = urlList.map(function(url) {
return exec('curl --max-time 20 --connect-timeout 10 -iSs "' + url + '"', function (error, stdout, stderr) { });
});
Promise.all(pList).then(() => {
console.timeEnd('total');
}).catch((e) => {
console.log('error: ' + e);
});
I think it might be memory problem because of too many curl connections.
But how to figure out it?
Thank you in advance!
because util.promisify(childProcess.exec)() only receive string not string and function
So you must change it into
const pList = urlList.map(function(url) {
return exec('curl --max-time 20 --connect-timeout 10 -i "' + url + '"');
});

Canva publish extension API : Endpoint never get call

I try to make a Canva App with a publish extension.
I just follow the Quick start (https://docs.developer.canva.com/apps/extensions/publish-extensions/quick-start) with Glitch and it work well on it.
But when I try to put in on my own public host name, with a other port (like http://mydomaine.com:3000) Canva NEVER call my endpoint. I just write a log file of every action on my app post and I never get a update on it, and when I try the app on Canva.com it just show me a error message.
//Copy from the Quick Start
app.post('/publish/resources/upload', async (request, response) => {
try{
writeLog("Uploading file");
await fs.ensureDir(path.join(__dirname, 'export'));
// Get the first asset from the "assets" array
const [asset] = request.body.assets;
// Download the asset
const image = await jimp.read(asset.url);
const filePath = path.join(__dirname, 'export', asset.name);
await image.writeAsync(filePath);
// Respond with the URL of the published design
response.send({
type: 'SUCCESS',
url: url.format({
protocol: request.protocol,
host: request.get('host'),
pathname: asset.name,
}),
});
} catch (err) {
writeLog("ERROR (app.post('/publish/resources/upload'): " + err);
}
});
//Just log on the log file
function writeLog(log){
// fs.appendFile(path.join(__dirname, '/log/' + `${month}/${date}/${year}` +'log.txt'), dateDisplay + "|" + log + "\n", (err) => {
// if (err) throw err;
// });
var today = new Date();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
var dateTime = date + ' ' + time;
natifFS.appendFile('log.txt', dateTime + '| '+ log + "\n", (err) => {
if (err) throw err;
});
}
Last thing, when I try to call a post request on the same endpoint as Canva (/publish/resources/upload) with Postman, I get a update on my log.txt file
If anyone has idea, thank you.

NodeJs deployment on cPanel: Missing Passenger.log and stderr.log files

I've deployed my NodeJs application on two different shared web hosting servers. The first one automatically generates stderr.log file and has a passenger file. However, the second server doesn't and I am therefore unable to see the error of the deployment. I've looked online but I couldn't find anything that can resolve my issue. I have also contacted the servers' customer service but they are not very helpful. Please let me know how can I create the stderr.log or passenger.log files! Thank you so much!
Had to add the following into the startup file (e.g. app.js) in order to generate the error logs. Didn't need to do this on the other server provider as it's default in their system.
var fs = require('fs');
var util = require('util');
var log_file = fs.createWriteStream(__dirname + '/debug.log', {flags : 'w'});
var log_stdout = process.stdout;
var log_stderr = process.stderr;
console.log = function(d) { //
log_file.write(util.format(d) + '\n');
log_stdout.write(util.format(d) + '\n');
log_stderr.write(util.format(d) + '\n');
};
// var out = fs.openSync('./output.log', 'a')
// , err = fs.openSync('./error.log', 'a');
// require('child_process').spawn('./server', [], {
// detached : true,
// stdio : ['ignore', out, err]
// });
var access = fs.createWriteStream(__dirname + '/stdout.log', {flags : 'w'});
process.stdout.write = process.stderr.write = access.write.bind(access);
process.on('uncaughtException', function(err) {
console.error((err && err.stack) ? err.stack : err);
});

Stop nodejs child_process with browser api call

I have vue (axios) making a get call to an express route which triggers a child_process of ffmpeg in an infinite loop. ffmpeg streams one file over udp , on close it re calls itself and streams another file.
I'd like to be able to kill this process from a button on a web page, but can't seem to work it out.
This is my express route code
router.get('/test', function(req, res) {
const childProcess = require('child_process');
const fs = require('fs')
const path = require('path')
//Grabs a random index between 0 and length
function randomIndex(length) {
return Math.floor(Math.random() * (length));
}
function Stream () {
const FILE_SRC = '/path/to/file'
//Read the directory and get the files
const dirs = fs.readdirSync(FILE_SRC)
.map(file => {
return path.join(FILE_SRC, file);
});
const srcs_dup = [];
const hashCheck = {}; //used to check if the file was already added to srcs_dup
var numberOfFiles = dirs.length - 1; //OR whatever # you want
console.log(numberOfFiles)
//While we haven't got the number of files we want. Loop.
while (srcs_dup.length < numberOfFiles) {
var fileIndex = randomIndex(dirs.length-1);
//Check if the file was already added to the array
if (hashCheck[fileIndex] == true) {
continue; //Already have that file. Skip it
}
//Add the file to the array and object
srcs_dup.push(dirs[fileIndex]);
hashCheck[fileIndex] = true;
}
var chosen = "'" + srcs_dup[0] + "'"
var call = "ffmpeg -re -i " + chosen + " -content_type audio/mpeg -f mp3 udp://224.1.2.3:1234"
const stop = childProcess.exec(call, { shell: true });
stop.stdout.on('data', function (data) {
console.log('stdout: ' + data.toString());
});
stop.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
stop.on('close', (code) => {
console.log ('child exited with code ' + code)
Stream();
});
stop.on('error', function(err) {
console.log('sh error' + err)
});
}

Download a file from S3 to Local machine

I am trying to download an audio(mp3) file from AWS S3 to local computer. It works fine when I execute on local host, but after after deploying same code onto AWS. It's downloading files to server machine instead of User's local machine.
Tried these two versions. Both are doing in same way
Version 1:
const key = track.audio_transcode_filename.substring(20);
var s3Client = knox.createClient(envConfig.S3_BUCKET_TRACKS);
const os = require('os');
const downloadPath = os.homedir().toString();
const config =require('../../config/environment');
const fs = require('fs');
var filePath=downloadPath + "\\Downloads\\" + track.formatted_title + ".mp3";
if (fs.existsSync(filePath)) {
var date = new Date();
var timestamp = date.getTime();
filePath=downloadPath + "\\Downloads\\" + track.formatted_title + "_" + timestamp + ".mp3";
}
const file = fs.createWriteStream(filePath);
s3Client.getFile(key, function(err, res) {
res.on('data', function(data) { file.write(data); });
res.on('end', function(chunk) { file.end(); });
});
version 2:
var audioStream = '';
s3Client.getFile(key, function(err, res) {
res.on('data', function(chunk) { audioStream += chunk });
res.on('end', function() { fs.writeFile(filePath + track.formatted_title + ".mp3", audioStream, 'binary')})
});
Thanks,
Kanth
Instead of getting the file and sending to client again, how about getting the url of the file and redirecting the client?
Something like:
s3Client.getResourceUrl(key, function(err, resourceUrl) {
res.redirect(resourceUrl);
)};
You'll need to send it to the user. So, I think you have an expressJS and the user can get the element using your API endpoint.
After all you have done in your question, you will need to send it to the user.
res.sendFile('/path/to/downloaded/s3/object')
Thank you both #Rashomon and #Martin do santos.
I'had to add client side script to read response stream and download file in the following way
downloadTrack(track).then((result) =>{
//var convertedBuffer = new Uint8Array(result.data);
const url = window.URL.createObjectURL(new Blob([result.data],{type: 'audio/mpeg'}));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', track.formatted_title + '.mp3');
document.body.appendChild(link);
link.click();
}, (error) =>{
console.error(error);
})

Resources