Atif Ali
Atif Ali

Reputation: 2757

Create multiple ftp clients to fetch files from different servers respectively. Is this possible in node?

So in my setup I have about 7 different ftp servers running on my network, and I want to be able to create multiple ftp clients in my node app to fetch some files from these servers respectively. I was wondering if that is even possible or not? I am looking at using the ftp npm package: https://www.npmjs.com/package/ftp

I have tried a couple things like the following where I create multiple instances of the client in an array and then spawn them off by doing a connect at the end of the iteration.

// Create all the clients for each host
// Note that config here is just a JSON object I read at the start
numAddresses = Object.keys(config.addresses).length; //7
clients=[];
for (address in config.addresses) {
    // current address being processed
    console.log(config.addresses[address]);
    // create a new client for this address
    clients[address] = createClient(path);
    // update the settings for this new client based on address
    // note we keep the default anonymous login credential
    // you can change it here though
    connectionSettings.host = config.addresses[address].ip;
    connectionSettings.port = config.addresses[address].port;
    console.log(connectionSettings);
    // connect the current client with the associated settings
    clients[address].connect(connectionSettings);
}

// creates a ftp client and returns it
function createClient(path) {
    var client = new Client();
    // define wait for the server handshake (greeting)
    client.on('greeting', afterGreeting);
    return client;
}
// handles the flow after server handshake (greeting)
function afterGreeting(msg, client) {
    console.log(msg);
    // define wait for the server 'ready' state
    client.on('ready', afterReady);
}
// handles the flow after server 'ready' state
function afterReady() {
    console.log('ready');
    performListing(path);
}
// handles the listing of the files
function performListing(path) {
    console.log('fetching from:'+path);
    client.list(path, performFetch);
}
// handles the fetching of the files
function performFetch(err, list){
    if (err) throw err;
    list.forEach(function (element, index, array) {
        console.log('now copying: '+element.name);
    });
    client.end();
}

I expected this to just spawn off all the instances of those clients in the loop but I get this error:

D:\node_workspace\ftp\main.js:52
    client.on('ready', afterReady);
TypeError: Cannot read property 'on' of undefined

I think I am running into some very basic error with my assumptions of how node works (I am a beginner). Any help would be appreciated.

Upvotes: 0

Views: 584

Answers (1)

Sebastian Waldbauer
Sebastian Waldbauer

Reputation: 667

Try the following code...

var Client = require("ftp");

numAddresses = Object.keys(config.addresses).length;

clients = [];
for (address in config.addresses) {
    // current address being processed
    console.log(config.addresses[address]);
    // create a new client for this address
    clients[address] = createClient(path);
    // update the settings for this new client based on address
    // note we keep the default anonymous login credential
    // you can change it here though
    connectionSettings.host = config.addresses[address].ip;
    connectionSettings.port = config.addresses[address].port;
    console.log(connectionSettings);
    // connect the current client with the associated settings
    clients[address].connect(connectionSettings);
}

function createClient(path) {
    var c = new Client();
    c.on('greeting', (msg) => {
        afterGreeting(msg, c);
    });
    return c;
}

function afterGreeting(msg, client) {
    console.log(msg);
    client.on('ready', () => {
        afterReady(client);
    });
}

function afterReady(client) {
    console.log('ready');
    performListing(path, client);
}

function performListing(path, client) {
    console.log('fetching from:' + path);
    client.list(path, (err, list) => {
        performFetch(err, list, client);
    });
}

function performFetch(err, list, client) {
    if (err) throw err;
    list.forEach(function (element, index, array) {
        console.log('now copying: ' + element.name);
    });
    client.end();
}

Updated

var Client = require("ftp");

numAddresses = Object.keys(config.addresses).length;

clients = [];
for (address in config.addresses) {
    // current address being processed
    console.log(config.addresses[address]);
    // create a new client for this address
    clients[address] = createClient(path);
    // update the settings for this new client based on address
    // note we keep the default anonymous login credential
    // you can change it here though
    connectionSettings.host = config.addresses[address].ip;
    connectionSettings.port = config.addresses[address].port;
    console.log(connectionSettings);
    // connect the current client with the associated settings
    clients[address].connect(connectionSettings);
}

function createClient(path) {
    // initialize new client
    var c = new Client();

    // official npm documentation https://www.npmjs.com/package/ftp#events
    // tells us, that greeting returns a string so we need to pass a callback
    // to c.on('greeting', callback)
    // we could either write function(msg) { } or short form (msg) => { }
    c.on('greeting', (msg) => {
        afterGreeting(msg, c);
    });
    return c;
}

function afterGreeting(msg, client) {
    console.log(msg);

    // ready needs a callback too but returns nothing, only calls this callback
    // if ready is ready. Kappa.
    client.on('ready', () => {
        afterReady(client);
    });
}

function afterReady(client) {
    console.log('ready');
    performListing(path, client);
}

function performListing(path, client) {
    console.log('fetching from:' + path);

    // client.list returns an err if we encounter an error and a list
    // our callback is written in shortform (err, list) => { } so we're
    // passing those callback data to this anonymous function
    client.list(path, (err, list) => {
        performFetch(err, list, client);
    });
}

function performFetch(err, list, client) {
    if (err) throw err;
    list.forEach(function (element, index, array) {
        console.log('now copying: ' + element.name);
    });
    client.end();
}

Answer to question: Depends on your program. You always can rewrite and optimize a program.

Upvotes: 1

Related Questions