Распаковка файла и загрузка на S3 - PullRequest
0 голосов
/ 28 августа 2018

Маршрут на узле берет zip-файл, и оттуда я распаковываю его в память и загружаю в S3-корзину. Все работает нормально, но я борюсь с разрешением после того, как все файлы из zip-файла сделаны.

function unzipAndUploadToS3(fileInfo) {
    return new Promise((resolve, reject) => {
        fs.createReadStream(fileInfo.zip.path)
            .pipe(unzipper.Parse())
            .pipe(etl.map(entry => {
                if (checkEntry(entry.path)) {
                    fileInfo.name = entry.path;
                    entry
                        .buffer()
                        .then(content => {
                            fileInfo.data = content;
                            AWS.uploadToS3(fileInfo).then(result => {
                                console.log(result.Location);
                                resolve(result.Location);  //ALWAYS Resolves here
                            }).catch(err => {
                                console.error(err);
                                reject(err);
                            })
                        })
                }
                else
                    entry.autodrain();
            }))
    });
}

Я пробовал Promise.all и Async / Await, но, похоже, я обдумываю это.

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Вот что у меня получилось. Это использует unzipper, etl и lodash.

function unzipAndUploadToS3(fileInfo) {
    return new Promise((resolve, reject) => {
        var filesToProcess = [];
        var filesStream = fs.createReadStream(fileInfo.zip.path)
            .pipe(unzipper.Parse())
            .pipe(etl.map(entry => {
                if (checkEntry(entry.path)) {
                    fileInfo.name = entry.path.substr(entry.path.indexOf('/') + 1, entry.path.length);
                    entry
                        .buffer()
                        .then(content => {
                            fileInfo.data = content;
                            var newObj = _.clone(fileInfo);  //need to clone object because of object reference in assignment
                            var promise = new Promise(function(resolve, reject) {  //create new promise to upload to S3
                                AWS.uploadToS3(newObj).then(result => { //a function in another module uses aws-sdk
                                    resolve(result)
                                }).catch(err => reject(err));
                            })
                            filesToProcess.push(promise);  //push this promise into an array of promises
                        })
                }
                else
                    entry.autodrain();
            }))
        filesStream.on('readable',  function () { console.log('readable');  })
            .on('data',  function (data) { console.log('data', data);  })
            .on('error', function (err)  {
                console.error('Error', err);
                reject(err);
            })
            .on('end',   function ()     {
                Promise.all(filesToProcess).then(values => {    //process all the promises
                    console.log("values>", values);
                    resolve(values);
                }).catch(err => {reject(err)});
            })
    });
}
0 голосов
/ 28 августа 2018

Я никогда не использовал etl раньше, но в их документации есть комментарий, который говорит

Переключение с цепочки на поток обещаний ...

А затем дает код .promise().then(...). Вы говорите, что пробовали Promise.all, но не говорите как, поэтому я не знаю, пробовали ли вы это уже. Но это направление, в котором я мог бы подумать:

function unzipAndUploadToS3(fileInfo) {
  return new Promise((resolve, reject) => {
    fs.createReadStream(fileInfo.zip.path)
      .pipe(unzipper.Parse())
      .pipe(etl.map(entry => {
        if (checkEntry(entry.path)) {
          fileInfo.name = entry.path;
          return entry.buffer() //<- return promise
            .then(content => {
              fileInfo.data = content;
              return AWS.uploadToS3(fileInfo) //<- return promise
            })
        }
        else
          entry.autodrain();
      }))
      .promise().then(awsPromises => Promise.all(awsPromises)) //<- return promise
      .then(x => resolve('x should be an array of s3 results'))
      .catch(err => reject(err));
  });
}

Чтобы это работало, хотя все обещания должны быть надлежащим образом связаны друг с другом для буферизации записи и затем загружены в s3. Я отметил важные результаты, чтобы сохранить связь с комментариями.

Еще кое-что, что выглядит немного странно для меня: я не могу поверить, что вы можете продолжать использовать один и тот же fileInfo с несколькими такими файлами. Для меня это похоже на состояние гонки: закончится ли предыдущая загрузка до того, как следующий файл перезапишет fileInfo.data и fileInfo.name? Полагаю, вам лучше создать новый объект fileInfo внутри вашей карты, а не использовать один и тот же для всех файлов в zip-файле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...