I'm working on a Node JS program to connect to a remote SFTP server to copy log files. I'm using this NPM package. ssh2-sftp-client
const main = () => {
const servers = ['server list'];
servers.forEach((s) => {
const sftp = new Client();
// Connect to the server
sftp.connect({
host: s,
port: '22',
username: '',
password: '',
}).then(() => logger.log(`Connected to ${s}`))
// get list of directories
.then(() => sftp.list(rootLogPath))
.then((dirs) => {
dirs.forEach((d) => {
const target = createTargetDirectory(d.name);
// list all files in the directory
sftp.list(`${rootLogPath}/${d.name}`)
.then((files) => {
// filter only today's files
const todayFiles = files.filter((f) => f.type === '-' && moment().format('MMDDYYYY') === moment(f.modifyTime).format('MMDDYYYY'));
// copy today's files into target
todayFiles.forEach((f) => {
sftp.get(`${rootLogPath}/${d.name}/${f.name}`, `${target}/${f.name}`)
.then(() => logger.log(`Copied ${f.name} from ${d.name} located on ${s}`));
});
});
});
return sftp.end();
})
.catch(() => logger.log(`Connection to ${s} failed`));
});
};
main();
The code is working as expected but the problem is I'm not able to terminate the session. The program just waits after its completed the copy files operation. The sftp.end() call is prematurely closing out connection before copying is complete. If I remove that program just waits after copy is completed.
I'm not sure where to write the sftp.end() line to terminate the program.
EDIT 1: Updated code using Promise.all and making use of async/await now.
Split my code into pieces and now making use of async/await for better readability. Program now ends fine. no more waiting or hanging but the problem is files are not copied. I see a console message "Copied files from source directory".
const copyTodayFiles = async (src) => {
try {
let fileList = await sftp.list(`${rootLogPath}/${src}`);
fileList = fileList.filter(
(f) => f.type === '-' && moment().format('MMDDYYYY') === moment(f.modifyTime).format('MMDDYYYY'),
);
const target = createTargetDirectory(src);
if (target) {
fileList.forEach(async (f) => {
try {
await sftp.get(`${rootLogPath}/${src}/${f.name}`, `${target}/${f.name}`);
logger.log(`Copied ${f.name}`);
} catch (error) {
logger.log(`Failed to copy ${f.name}`);
}
});
console.log(`Copied files from ${src}`);
}
} catch (error) {
logger.log(`Failed to read files from ${src}`);
logger.log(error);
}
};
const workOn = async (server) => {
sftp = new Client();
const config = {
host: server,
port: '22',
username: '',
password: '',
};
try {
await sftp.connect(config);
logger.log(`Connection to ${server} is successful.`);
const logDir = await sftp.list(rootLogPath);
Promise.all(logDir.map((d) => copyTodayFiles(d.name))).then(() => sftp.end());
// logDir.forEach(async (d) => copyTodayFiles(d.name));
} catch (error) {
logger.log(`Connection to ${server} failed.`);
logger.log(error);
}
};
const main = () => {
const servers = ['server list'];
Promise.all(servers.map((s) => workOn(s)));
};
main();
forEachloop which executes synchronously and doesn't save function return values, and immediately callsftp.end()whenforEachreturns. Look up questions on the use offorEachin asynchronous code before proceeding. :-) - traktor