I am using the sftps NPM to connect to a SFTP server using username/password authentication and upload a file. This works beautifully when successful; however, if provided invalid authentication information, after several minutes it emits an ECONNRESET error which crashes my entire application.
Looking at the source of the sftps module, it appears to use child_process.spawn to run the shell commands, and looks like it should be capturing any errors gracefully:
var sftp = spawn(shellCmd, shellOpts);
var data = "";
var error = "";
sftp.stdout.on('data', function (res) {
data += res;
});
sftp.stderr.on('data', function (res) {
error += res;
});
function finished(err) {
error = error.split('\n').filter(function(line) {
if (/^Connected to /.test(line)) return false;
return true;
}).join('\n');
data = data.split('\n').filter(function(line) {
if (/^sftp> /.test(line)) return false;
return true;
}).join('\n');
if (callback) {
if (err) {
callback(err, { error: error || null, data: data });
} else if (error) {
callback(null, { error: error, data: data });
} else {
callback(null, { error: null, data: data });
}
callback = null;
}
}
sftp.on('error', finished);
sftp.on('exit', function (code) {
if (code === 0) {
finished();
} else {
finished('Nonzero exit code: ' + code);
}
});
sftp.stdin.write(cmdString, 'utf8');
It looks like it has hooked into the stderr stream as well as capturing the error and exit events on the sub-process.
What else can I do to capture this ECONNRESET error and log it without killing the application?
Don't know if you're having the same problem that I was having, but I eventually solved it by attaching an event to stdin.on("error"). You could try this to see if that's the problem:
sftp.stdin.on("error", function (e)
{
console.log("STDIN ON ERROR");
console.log(e);
});
Related
What am I trying to do?
I want to clone multiple git repositories from nodejs.
How do I achieve that?
First I have this method in a separate file:
const exec = require("child_process").exec;
const { printError } = require("./printers");
function execute(command) {
console.log(`Running command: ${command}`);
let result = "";
let savedError = undefined;
return new Promise((resolve, reject) => {
const proc = exec(command, function (error, stdout, stderr) {
savedError = savedError || stderr || error;
result += stdout;
});
proc.on("close", (code) => {
if (code !== 0) {
console.error(
[
"================================================================",
`Command ${command} failed.`,
`Status code: ${code}`,
`Error message: ${savedError}`,
`Output: ${result}`,
"================================================================",
"",
].join("\n")
);
reject(result);
} else {
resolve(result);
}
});
});
Then I use it in my main module (code is abbreviated and bit simplified just so you can get the point:
const repoUrls = ["url1", "url2"]; // imagine these are real urls
async function main() {
const copyOfUrls = [...repoUrls];
while (copyOfUrls.length) {
try {
await execute(
`git clone ${copyOfUrls[0]} repositories/${repoUrlFileFriendly(
copyOfUrls[0]
)}`
);
console.log('fun fact - this console log never happens');
copyOfUrls.shift()
} catch (error) {
console.error("Failed to clone, see error:", error);
}
}
}
What is the problem?
Well, code works BUT after cloning first repo, the process exits (both the child process and the main one) and second repository is never even attempted to be cloned. (note the "console.log('fun fact - this console log never happens');").
I've been working on a "artwall" bot with, basically write to .json file command. I want for the bot to get the first message attachment, get it's url and save it to save.json.
If there's a an attachment present, everything works fine, but if the command was initiated with a url or without any arguments at all, it gives this error:
TypeError: Cannot read property 'url' of undefined
Here's the command code:
const fs = require('fs');
// Export code for command.
module.exports = {
// In name type name of this command to execute it.
name: 'done',
// In description type description.
description: 'N/A',
// In execute() {...} circle brackets type execution parameters.
execute(client, message, args) {
// Type command code here.
const safety = JSON.parse(fs.readFileSync('./assets/save.json', 'utf8'));
const currentdeg = JSON.parse(fs.readFileSync('./assets/currentDEBUG.json', 'utf8'));
// const attache = JSON.parse(fs.readFileSync('./assets/attach.json', 'utf8'));
if(safety == 'no') {
if(currentdeg == 'not claimed') {
message.channel.send('The wall is not claimed yet. Claim it by using `wol claim`');
}
else if(currentdeg == message.author.id) {
const Attachment = (message.attachments).array();
console.log(Attachment);
if (Attachment == []) {
if (!args) {
message.reply('there\'s no image present. Make sure you attached one message or used url.');
return;
}
else {
fs.writeFile('assets/currentDEBUG.json', JSON.stringify('not claimed', null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (claim)');
});
fs.writeFile('assets/attach.json', JSON.stringify(args[0], null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (attache)');
});
}
}
// stuff
fs.writeFile('assets/currentDEBUG.json', JSON.stringify('not claimed', null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (claim)');
});
fs.writeFile('assets/attach.json', JSON.stringify(Attachment[0].url, null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (attache)');
});
}
else {
// stuff
message.channel.send('The artwall was claimed by someone else already. Wait for them to finish their work.');
}
}
else {
message.channel.send('The artwall is locked right now. Please wait for the next event!');
}
},
};
Thanks in advance!
I'm trying to prevent the user to save a piece if it doesn't achieve some requirements.
Currently I'm doing it like this:
self.beforeSave = function(req, piece, options, callback) {
let success = true;
let error = "";
if (Array.isArray(piece._subevents) && piece._subevents.length) {
success = self.checkDateAndTimeCompabilitiyWithChildren(piece);
}
if (!success) {
self.apos.notify(req, "Check the compatibility between parent event and subevents", { type: "error" });
error = "Subevents are not compatible with parent event";
}
callback(error);
};
This works but the problem is it shows 2 errors notifications (the default and my custom), 1 because of callback(error) and 1 because of apos.notify.
Any idea how to stop the item of being saved and only show my notification?
Thanks in advance.
UPDATE 1:
As Tom pointed out, my code looks like this now:
// lib/modules/events/public/js/editor-modal.js
apos.define('events-editor-modal', {
extend: 'apostrophe-pieces-editor-modal',
construct: function(self, options) {
self.getErrorMessage = function(err) {
if (err === 'incompatible') {
apos.notify('A message suitable for this case.', { type: 'error' });
} else {
apos.notify('A generic error message.', { type: 'error' });
}
};
}
});
// lib/modules/events/index.js
var superPushAssets = self.pushAssets;
self.pushAssets = function() {
superPushAssets();
self.pushAsset("script", "editor-modal", { when: "user" });
};
self.beforeSave = async function(req, piece, options, callback) {
return callback("incompatible")
};
For testing purposes I'm just returning the error in beforeSave. The problem is that an exception is being thrown in the browser console and the modal is not properly rendered again. Here's a screenshot about what I'm talking:
I'm trying to debug it and understand what's happening but no clue yet.
In your server-side code:
self.beforeSave = function(req, piece, options, callback) {
let success = true;
if (Array.isArray(piece._subevents) && piece._subevents.length) {
success = self.checkDateAndTimeCompabilitiyWithChildren(piece);
}
if (!success) {
return callback('incompatible');
}
return callback(null);
};
And on the browser side:
// in lib/modules/my-pieces-module/public/js/editor-modal.js
apos.define('my-pieces-module-editor-modal', {
extend: 'apostrophe-pieces-editor-modal',
construct: function(self, options) {
self.getErrorMessage = function(err) {
if (err === 'incompatible') {
return 'A message suitable for this case.';
} else {
return 'A generic error message.';
}
};
}
});
If the error reported by the callback is a string, it is passed to the browser. The browser can then recognize that case and handle it specially. 'my-pieces-module-editor-modal' should be substituted with the name of your pieces module followed by -editor-modal.
I need combine two streams in parallel way. I want to use these streams to write into two files some generated information.
I have done the first stream (stream1). It looks like this:
'use strict';
var fs = require('fs');
var stream1 = fs.createWriteStream("random1.txt");
let ln = 1000000;
let j = 0;
function generateRandom()
{
var reslt = true;
do {
ln--;
j++;
if (ln === 0) {
stream1.write(...write randon number...);
stream1.end();
} else {
reslt = stream1.write(...write randon number...);
}
} while (ln > 0 && reslt);
if (ln > 0) {
stream1.once('drain', generateRandom);
}
}
stream1.on('error', (err) => {throw err;});
var stream1Promise = new Promise((resolve, reject)=>{
try {
generateRandom();
});
} catch (error) {
reject(error);
}
});
stream1Promise
.then(function(callback) {
if (typeof callback === 'function') {
callback();
}
}, function(error) {
console.log("Error occurred: ", error);
stream1.end();
});
But I don't understand how to add another one stream stream2 so that it writes different random information to another file.
I've tried to use process.nextTick in callback of stream1.write to switch my streams, but I get all time "FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory" error.
Could anyone help me?
Thanks.
The error message that I keep getting is the following:
assert.js:92
throw new assert.AssertionError({
^
AssertionError: abnormal phantomjs exit code: -1073741819
at Console.assert (console.js:102:23)
at ChildProcess.<anonymous> (C:\Users\file_path...\node_modules\phantom\phantom.js:132:28)
at ChildProcess.emit (events.js:98:17)
at Process.ChildProcess._handle.onexit (child_process.js:810:12)
Program node app.js exited with code 8
The break happens at random, sometimes after inserting over a thousand rows into postgreSQL, sometimes after just a handful of rows.
I'm fairly sure that the error is occuring in the following function inside of my code, based on a lot of different console.logs that I have put throughout the code. Also, I think that assert.js:92 is from Chai:
function getNetworkTraffic(networkUrl,senderEmail) {
phantom.create(function (ph) {
ph.createPage(function (page) {
page.set("onResourceRequested", function (req) {
referrerValue = "";
referrerName = "";
linkRedirectUrl="";
console.log('Fetching network traffic...')
for (i in req.headers) {
allReferrals = req.headers[i]
if (allReferrals.name == "Referer"){
referrerName = allReferrals.name
referrerValue = allReferrals.value
}
}
linkUrl = req.url
if(req.redirectURL){
linkRedirectUrl = redirectURL
}
singleReq = {"referrerName":referrerName,"referrerValue":referrerValue,"requestUrl":linkUrl,"redirectURL":linkRedirectUrl, "parent_url":networkUrl, "source": "email", "senderEmail":senderEmail}
// insertNetworkTrafficPg(singleReq)
});
page.set("onResourceReceived", function (res) {
linkRedirectUrl = "";
responseUrl = res.url
if(res.redirectURL){
linkRedirectUrl = res.redirectURL
}
singleRes = {"responseUrl":responseUrl,"redirectURL":linkRedirectUrl,"parent_url":networkUrl,"source": "email", "senderEmail":senderEmail}
// insertNetworkTrafficPg(singleRes)
});
try{
page.open(networkUrl, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address');
}
console.log('Opening web address...');
ph.exit();
});
} catch(err) {
console.log(err)
}
});
}, {
dnodeOpts: {
weak: false
}
});
}
It's possible to use phantomjs with node, but keep in mind that this is a bridge. Also, it's really not intended for a lot of scraping, so perhaps you are opening too many threads and its a stackoverflow, but breaking with another message. You might want to try using something like python-shell to run a script for python to do your scraping.