Как я могу загружать/выгружать несколько файлов одновременно с помощью SFTP через модуль ssh2 Node.js (в приложении Electron)?

Я создаю простой SFTP-клиент с Electron и пытаюсь загрузить или загрузить несколько файлов одновременно, используя модуль ssh2 и SFTPStream в этом модуле. Я пробовал много разных структур методов, некоторые из которых включают использование es6-promise-pool. Каждая попытка, которую я предпринимаю, приводит к тому, что один файл из массива файлов для передачи передается правильно, а затем

MaxListenersExceededWarning: Обнаружена возможная утечка памяти EventEmitter. 11 прослушивателей sftp_message добавлены в [EventEmitter]. Используйте emitter.setMaxListeners() для увеличения лимита

сообщение отображается в консоли, а остальные файлы не передаются. Я не уверен, как изменить структуру моего метода, чтобы этого не произошло. Я использую ipcRenderer, чтобы указать ipcMain выполнить методы, которые я покажу здесь (например, вот моя структура для загрузки файлов).

let counter = 0;

// Upload local file to server
ipcMain.on('upload_local_files', (event, args) => { // args[0] is connection settings, args[1] is array of file paths
  let conn = new Client();
  conn.on('ready', () => {
    let pool = new PromisePool(uploadFileProducer(conn, args[1]), 10);
    pool.start().then(() => {
      conn.end();
      counter = 0;
      let tempArgs = [];
      tempArgs.push(curLocalDir);
      tempArgs.push(curRemoteDir);
      event.sender.send('local_upload_complete', tempArgs);
    });
  }).connect(args[0]);
});

// Producer used in promise pool to upload files
function uploadFileProducer(conn, files){
  if(counter < 100 && counter < files.length){
    counter++;
    return(uploadFile(conn, files[counter - 1]));
  }else{
    return null;
  }
}

// Function used to upload files in promise pool
function uploadFile(conn, file){
  return new Promise((resolve, reject) => {
    conn.sftp((error, sftp) => {
      return sftp.fastPut(file, curRemoteDir + file.substring(file.lastIndexOf('/') + 1), {}, (error) => {
        resolve(file);
      });
    });
  });
}

По общему признанию, использование пулов промисов для меня новое, и я не уверен, правильно ли я их использую. В другом сообщении на эту тему использовались пулы промисов, чтобы предотвратить возникновение проблемы, с которой я столкнулся, но в этом примере не использовалось приложение Electron (я не знаю, актуально ли это). Я ценю любую помощь, которую я могу получить!


person mandrews6975    schedule 21.12.2019    source источник
comment
Вы уверены, что ничего не загружено? Потому что это просто предупреждение, и это нормально, если вы загружаете несколько файлов одновременно.   -  person Marcos Casagrande    schedule 21.12.2019
comment
Загружается только первый файл в массиве, выдается это предупреждение, а затем соединение закрывается без загрузки остальных файлов в массиве.   -  person mandrews6975    schedule 21.12.2019
comment
Предупреждение не имеет к этому никакого отношения, я отправляю ответ.   -  person Marcos Casagrande    schedule 21.12.2019


Ответы (1)


Проблема не в Warning, это просто предупреждение и нормально в вашем текущем варианте использования. Проблема с загрузками заключается в неправильном использовании PromisePool.

Я предполагаю, что вы используете es6-promise-pool

Вы должны передать функцию производителя обещания в конструктор, но вместо этого вы вызываете функцию и передаете обещание, поэтому загружаются только отдельные файлы.

Вы должны передать производителя, не вызывая его, или создать производителя, который возвращает функцию, или использовать генератор.

Конструктор PromisePool принимает в качестве первого аргумента функцию, создающую Promise.

function *uploadFileProducer(conn, files) {
    for(const file of files)
        yield uploadFile(conn, file);
}

Теперь вы можете позвонить:

let pool = new PromisePool(uploadFileProducer(conn, args[1]), 10)

И PromisePool будет правильно повторять итератор, возвращаемый функцией генератора, и соответствующим образом обрабатывать параллелизм.

Вы также можете создать функцию, которая возвращает Promise при каждом вызове.

function uploadFileProducer(conn, files) {
  files = files.slice(); // don't want to mutate the original
  return () => uploadFile(conn, files.shift())
}

Что касается предупреждения, это нормально, если вы загружаете несколько вещей одновременно, в этом случае вы можете увеличить лимит, используя:

emitter.setMaxListeners(n)
person Marcos Casagrande    schedule 21.12.2019