var FtpClient = require("ftp"); // connections are reused to make things faster and avoid too much problems const connections = {}; setInterval(() => { for(let key in connections){ if(connections[key].date + (1000*120) < new Date().getTime()){ connections[key].conn.end(); delete connections[key]; } } }, 5000); function connect(params){ if(connections[JSON.stringify(params)]){ connections[JSON.stringify(params)].date = new Date().getTime(); return Promise.resolve(connections[JSON.stringify(params)].conn); }else{ let c = new FtpClient(); c.connect({ host: params.hostname, port: params.port || 21, user: params.username, password: params.password }); return new Promise((done, err) => { c.on('ready', function(){ clearTimeout(timeout); done(c); connections[JSON.stringify(params)] = { date: new Date().getTime(), conn: c } }); c.on('error', function(error){ err(error) }) // because of: https://github.com/mscdex/node-ftp/issues/187 let timeout = setTimeout(() => { err('timeout'); }, 5000); }); } } module.exports = { test: function(params){ return connect(params) .then(() => Promise.resolve(params)) }, cat: function(path, params){ return connect(params) .then((c) => { return new Promise((done, err) => { c.get(path, function(error, stream) { if (error){ err(error); } else{ done(stream); } }); }); }); }, ls: function(path, params){ return connect(params) .then((c) => { return new Promise((done, err) => { c.list(path, function(error, list) { if(error){ err(error) } else{ list = list .map(el => { return { size: el.size, time: new Date(el.date).getTime(), name: el.name, type: function(t){ if(t === '-'){ return 'file'; }else if(t === 'd'){ return 'directory'; }else if(t === 'l'){ return 'link'; } }(el.type), can_read: null, can_write: null, can_delete: null, can_move: null } }) .filter(el => { return el.name === '.' || el.name === '..' ? false : true }); done(list); } }) }) }) }, write: function(path, content, params){ return connect(params) .then((c) => { return new Promise((done, err) => { c.put(content, path, function(error){ if (error){ err(error)} else{ done('ok'); } }); }); }) }, rm: function(path, params){ return connect(params) .then((c) => { return new Promise((done, err) => { c.delete(path, function(error){ if(error){ c.rmdir(path, true, function(error){ if(error) { err(error) } else{ done('ok dir'); } }); } else{ done('ok'); } }); }); }); }, mv: function(from, to, params){ return connect(params) .then((c) => { return new Promise((done, err) => { c.rename(from, to, function(error){ if(error){ err(error) } else{ done('ok') } }); }); }); }, mkdir: function(path, params){ return connect(params) .then((c) => { return new Promise((done, err) => { c.mkdir(path, function(error){ if(error){ err(error) } else{ done('ok') } }); }); }); }, touch: function(path, params){ return connect(params) .then((c) => { return new Promise((done, err) => { c.put(Buffer.from(''), path, function(error){ if (error){ err(error)} else{ done('ok'); } }); }); }); } };