Ad

Node.js [promise-ftp] - Unable To Make Data Connection (Error: Connect ECONNREFUSED...) While Downloading Multiple Files From FTP

- 1 answer

I'm getting this error while trying to download multiple images from ftp using promise-ftp. I'm able to see some images being downloaded before this error.

Unable to make data connection( Error: connect ECONNREFUSED...)

In my scenario, client sends specific directory paths of ftp from which all the images should be downloaded to server.

Here is my code:

iniatially uploadData consists of data from client from which directory paths are obtained.

router.post("/addPhotos", async (req, res) => {
  try {
    let uploadData = req.body;

    if (!uploadData) {
      handleError("Error! Invalid data received.", res);
      return;
    }

    await getPhotosWithCaptionsAndPath(uploadData)
      .then(uDataWithCaptionsAndPath => {
        uploadData = uDataWithCaptionsAndPath;

        res.status(200).send({
          data: "Images Uploaded successfully!",
          success: true,
          error: null
        });
      })
      .catch(err => {
        handleError(err, res);
      });

    //insert uploadData to db . . .
  } catch (err) {
    handleError(err, res);
  }
});

getPhotosWithCaptionsAndPath = uploadData => {
  return new Promise(async (resolve, reject) => {
    try {
      let output = [];
      let fileCount = 0;

      //get total # of images in all directories
      await getfileCount(uploadData)
        .then(fc => (fileCount = fc))
        .catch(err => reject(err));

      //download images and generate output array for db rows
      const ftp = new PromiseFtp();
      await ftp
        .connect({
          host: env.ftp.host,
          user: env.ftp.user,
          password: env.ftp.password
        })
        .then(serverMessage => {
          //looping through each directory
          uploadData.forEach(async (v, i) => {
            // calc directory path
            /* prettier-ignore */
            let uri = `/${
              v.schoolName
            }/${
              v.studentClass.toString()
            }-${
              v.studentSection
            }/${
              v.studentName
            }`;

            await ftp
              .list(uri, false)
              .then(list => {
                //looping through each image file
                list.forEach((val, index) => {
                  uploadFtpFile(ftp, uri, val, output)
                    .then(outputFromUFF => {
                      output = outputFromUFF;
                      if (fileCount === output.length) {
                        ftp.end();
                        resolve(output);
                      }
                    })
                    .catch(err => reject(err));
                });
              })
              .catch(err => reject(err));
          });
        });
    } catch (err) {
      reject(err);
    }
  });
};

uploadFtpFile = (ftp, uri, val, output) => {
  return new Promise((resolve, reject) => {
    try {
      ftp.get(uri + "/" + val.name).then(stream => {
        let fileName = `ph${Date.now()}.png`;
        let file = fs.createWriteStream("./uploads/" + fileName);
        output.push({
          url: fileName,
          caption: val.name.replace(/\.[^/.]+$/, "")
        });

        stream.pipe(file);
        stream.once("close", () => {
          resolve(output);
        });
        stream.once("error", reject);
      });
    } catch (err) {
      reject(err);
    }
  });
};

getfileCount = uploadData => {
  return new Promise((resolve, reject) => {
    try {
      let fileCount = 0;
      const ftpC = new PromiseFtp();
      ftpC
        .connect({
          host: env.ftp.host,
          user: env.ftp.user,
          password: env.ftp.password
        })
        .then(serverMessage => {
          uploadData.forEach(async (v, i) => {
            /* prettier-ignore */
            let uri = `/${
            v.schoolName
          }/${
            v.studentClass.toString()
          }-${
            v.studentSection
          }/${
            v.studentName
          }`;
            await ftpC
              .list(uri, false)
              .then(async list => {
                fileCount += list.length;
                if (i === uploadData.length - 1) resolve(fileCount);
              })
              .catch(err => reject(err));
          });
        })
        .catch(err => reject(err));
    } catch (err) {
      reject(err);
    }
  });
};
Ad

Answer

There is a limit that is applied to FTP, so its not a good idea to bulk upload/download stuff from FTP, you need to convert your foreach loops to for loops this will allow each file to be processed in sequence, this may delay your process, but will be fail safe.

So you may change this snippet

for (let  i = 0; i < list.length; i++) {
  let val = list[i]
  uploadFtpFile(ftp, uri, val, output)
  .then(outputFromUFF => {
     output = outputFromUFF;
     if (fileCount === output.length) {
        ftp.end();
        resolve(output);
     }
   })
   .catch(err => reject(err));
}
Ad
source: stackoverflow.com
Ad