Как загрузить изображения из AWS в папку в метеоре

Следующий код работает. Но он загружает только одно изображение. Я хочу, чтобы он загружал несколько изображений и, если не слишком много проблем, поместил их в папку, возможно, в папку zip. По какой-то причине он не будет загружать более одной фотографии (при загрузке дополнительных изображений в сети происходит сбой сети). И я попытался реализовать JSZip, который я настроил, но я не мог понять, как затем использовать новый объект JSZip для инициирования загрузки с сервера. Кто-нибудь может предложить какой-нибудь код или указать мне правильное направление?

Желательно, чтобы это происходило на сервере.

На клиенте:

'click #download-all-photos': function (event, template) {
  Files.find({
     productId: this._id
  }).forEach((photo) => {

    Meteor.call('get.s3.image', photo, function (error, result) {
        if (error) {
           console.log(error);
        } else {

           function _arrayBufferToBase64(buffer) {
              var binary = '';
              var bytes = new Uint8Array(buffer);
              var len = bytes.byteLength;
              for (var i = 0; i < len; i++) {
                 binary += String.fromCharCode(bytes[i] );
              }
              return window.btoa(binary);
           }

           let base64 = _arrayBufferToBase64(result.data);

           base64 = 'data:' +result.mimeType+ ';base64,'+base64;

           let link = document.createElement('a');
           link.setAttribute('href', base64);
           link.setAttribute('download', result.fileName);
           link.click();
           link.remove();

        }
     });

  });

}

});

Сервер:

'get.s3.image': function (photo) {
  let fileType = '';
  let split = photo.url.split('.');
  fileType = split[split.length-1];

  let bucket = split[0].replace('https://', '');

  var s3 = new AWS.S3({
     accessKeyId: AWSAccessKeyId,
     secretAccessKey: AWSSecretAccessKey
  });

  let split2 = photo.url.split('/');
  let split3 = photo.url.split(split2[2] + '/');

  let fileName = '';
  fileName = split2[split2.length-1];

  let key = split3[1];

  let mimeType = mime.lookup(photo.url);

  let fut = new Future();

  s3.getObject(
     { Bucket: bucket, Key: key },
     function (error, data) {
        if (error) {
           console.log("Failed to retrieve an object: " + error);
           fut['return'](error);
           throw new Meteor.Error('500', error);
        } else {
           console.log("Loaded " + data.ContentLength + " bytes");

           fut['return']({
              mimeType: mimeType,
              fileName: fileName,
              data: data.Body
           });

        }
     }
  );

  return fut.wait();
},

Еще одна вещь, которую я попробовал, - это создание маршрута для загрузки изображения. Опять же, это работает, но я могу заставить его сделать только одно изображение. Я бы предпочел, чтобы он просматривал запрашиваемую коллекцию изображений и загружал их все в zip-папку:

Router.route('/download_file/:_id', {
name: 'download.file',
where: 'server',
action: function () {
  let res = this.response;

  let image = Files.findOne(this.params._id);

  if (!image) {
     res.writeHead(404, {'Content-Type': 'text/html'});
     res.end('404: No Images Found');
     return;
  }

  let mimeType = mime.lookup(image.url);

  let fileType = '';
  let split = image.url.split('.');

  fileType = split[split.length-1];
  let bucket = split[0].replace('https://', '');

  var s3 = new AWS.S3({
     accessKeyId: AWSAccessKeyId,
     secretAccessKey: AWSSecretAccessKey
  });

  let split2 = image.url.split('/');
  let split3 = image.url.split(split2[2] + '/');

  let key = split3[1];

  s3.getObject(
     { Bucket: bucket, Key: key },
     function (error, data) {
        if (error != null) {
           console.log("Failed to retrieve an object: " + error);
        } else {
           let headers = {
              'Content-Type': mimeType,
              'Content-Disposition': "attachment; filename=file."+fileType
           };
           res.writeHead(200, headers);
           res.end(data.Body, 'binary');
        }
     }
  );
}
});

1 ответ

Казалось, я решил свою проблему! Может быть, хакерский. У меня работает JSZip. Он получает файлы от S3, а затем отправляет их клиенту для загрузки в zip-архив (загружается через saveAs() из пакета метеора). Кажется, работает очень хорошо. Может быть, это может помочь кому-то еще.

Клиент:

'click #download-all-photos': function (event, template) {

  let JSZip = require('jszip');

  let zip = new JSZip();
  let folder = zip.folder('photos');

  let hasError = false;

  let fileName = '';
  if (this.mpn) fileName += this.mpn + '_';
  fileName += this.productNumber;

  let count = 0;
  let number = Files.find({ productId: this._id }).count();

  let downloaded = false;

  Files.find({ productId: this._id }).forEach((photo) => {

     Meteor.call('get.s3.image', photo, function (error, result) {
        if (error) {
           console.log(error);
        } else {
           folder.file(result.fileName, result.data);

           count++;

           if (count === number && !downloaded) {

              downloaded = true;

              let zipFile = zip.generate();

              let base64 = 'data:application/zip;base64,'+zipFile;

              fetch(base64)
                 .then(res => res.blob())
                 .then(blob => {
                    saveAs(blob, fileName + '.zip');
                 });

           }

        }
     });

  });

}

Сервер:

'get.s3.image': function (photo) {
  let fileType = '';
  let split = photo.url.split('.');
  fileType = split[split.length-1];

  let bucket = split[0].replace('https://', '');

  var s3 = new AWS.S3({
     accessKeyId: AWSAccessKeyId,
     secretAccessKey: AWSSecretAccessKey
  });

  let split2 = photo.url.split('/');
  let split3 = photo.url.split(split2[2] + '/');

  let fileName = '';
  fileName = split2[split2.length-1];

  let key = split3[1];

  let mimeType = mime.lookup(photo.url);

  let fut = new Future();

  s3.getObject(
     { Bucket: bucket, Key: key },
     function (error, data) {
        if (error) {
           console.log("Failed to retrieve an object: " + error);
           fut['return'](error);
           throw new Meteor.Error('500', error);
        } else {
           console.log("Loaded " + data.ContentLength + " bytes");

           fut['return']({
              mimeType: mimeType,
              fileName: fileName,
              data: data.Body
           });

        }
     }
  );

  return fut.wait();
},
Другие вопросы по тегам