2015-03-28 8 views
1

Я использую пакет CollectionFS с адаптером S3, и я рассмотрел несколько различных решений, но не могу заставить это работать правильно.Meteor CollectionFS: убедитесь, что изображение загружено перед отображением

Проблема: Несмотря на то, что файл/изображение загружается на S3 успешно, обратный вызов для успешной загрузки запускается, прежде чем безопасно отображать изображение. Это приводит к тому, что иногда отображается некорректное изображение.

Я узнал о обратном вызове fileObj.once("uploaded", function(){}), но, кажется, «загруженный» в основном означает отправку изображения на сервер. К тому времени загрузка S3 не произойдет. Временное обходное решение, которое я нашел, состоит в том, чтобы просто иметь setTimeout в течение 3-4 секунд, но это ненадежно.

Вот мой код загрузки:

FS.Utility.eachFile(event, function(file) { 
    Session.set('profilePhotoUploaded', false); 
    var newFile = new FS.File(file); 
    newFile.metadata = {owner: Meteor.userId()};  

    ProfileImages.insert(newFile, function (err, fileObj) { 
     if (err){ 
     console.log("error! - " + err); 
     } else { 
     // handle success depending what you need to do 

     var userId = Meteor.userId(); 

     // This does NOT run when image is stored in S3. I think it runs when the image reached the app server. 
     fileObj.once("uploaded", function() { 

      // timeout of 3 seconds to make sure image is ready to be displayed 
      // --- This is not a good solution and it image does is not always ready 
      setTimeout(function(){ 
       var uploadedImage = { 
        "profile.image.url": "/cfs/files/profileImages/" + fileObj._id 
       }; 
       Meteor.users.update(userId, {$set: uploadedImage}); 

       Session.set('profilePhotoUploaded', true); 
      }, 3000); 

      console.log("Done uploading!"); 
     }); 
    } 
    }); 
}); 

Есть другой обратный вызов, чтобы проверить, если изображение на самом деле было сохранено в S3? Я пробовал fileObj.once("stored", function(){}), но это не работает.

ответ

1

Я обнаружил, что fileObj.hasStored("profileImages") точно определяет, когда изображение хранится на S3. Поэтому после запуска процесса загрузки я запускаю таймер каждые 1 секунду, чтобы проверить, сохранено ли оно. Это может быть не лучшее решение, но это то, что сработало для меня.

FS.Utility.eachFile(event, function(file) { 
    Session.set('profilePhotoUploaded', false); 
    var newFile = new FS.File(file); 
    newFile.metadata = {owner: Meteor.userId()}; // TODO: check in deny that id is of the same user 

    ProfileImages.insert(newFile, function (err, fileObj) { 
     if (err){ 
     console.log("error! - " + err); 
     } else { 
     // handle success depending what you need to do 

     var userId = Meteor.userId(); 

     // Timer every 1 second 
     var intervalHandle = Meteor.setInterval(function() { 
            console.log("Inside interval"); 
            if (fileObj.hasStored("profileImages")) { 
             // File has been uploaded and stored. Can safely display it on the page. 
             var uploadedImage = { 
              "profile.image.url": "/cfs/files/profileImages/" + fileObj._id 
             }; 
             Meteor.users.update(userId, {$set: uploadedImage}); 

             Session.set('profilePhotoUploaded', true); 

             // file has stored, close out interval 
             Meteor.clearInterval(intervalHandle); 
            } 
           }, 1000); 
    } 
    }); 
}); 
+0

Это отстой, что на клиентской стороне еще нет обратного вызова, чтобы сообщить приложению, что файл был сохранен безопасно, но этот код нужно будет сделать сейчас. Благодаря! –

2

Проблема заключается в том, что крючок stored будет срабатывать, когда исходное изображение будет сохранено на сервере, поэтому, если вы создаете несколько копий (миниатюр), этот крючок будет стрелять до сохранения ваших эскизов. Вы можете проверить, какая версия миниатюры была сохранена, проверив аргумент storeName. В стороне сервера файл, в котором вы определяете ProfileImages коллекции добавить следующий код, заменив 'profilePhotoLarge' с именем, назначенным для FS.Store.S3 магазина:

ProfileImages.on('stored', Meteor.bindEnvironment(function(fileObj, storeName) { 
    if (storeName === 'profilePhotoLarge') { 
     Meteor.users.update({_id: fileObj.metadata.owner}, { 
      $set: { 
       'profile.image.url': 'https://your AWS region domain/your bucket name/your folder path/' + fileObj._id + '-' +fileObj.name() 
      } 
     }); 
    } 
}, function() { console.log('Failed to bind environment'); })); 

Для фотографий профиля я создал ведро S3 и установить разрешение, чтобы кто-нибудь для чтения файлов, поэтому я сохраняю URL-адрес изображения на S3, что может быть неверным в вашем случае. Поскольку объект пользователя реагирует на стороне клиента, это обновление приведет к автоматическому обновлению фотографии профиля.

+0

На самом деле, я думал, это действительно сработает. Но это не так. И я думаю, что причина упоминается https://github.com/CollectionFS/Meteor-CollectionFS/issues/351 - «сохраненное» событие в коллекции на сервере должно теперь работать правильно. Теперь вы также можете сделать fileObj.on («сохраненный», func) на сервере и fileObj.on («uploaded», func) на клиенте. В конце концов мы планируем «сохранить» на клиенте для коллекций и fileObjs, но это сложнее и еще не реализовано. –

+0

Итак, я пытаюсь получить «сохраненный» обратный вызов на клиенте. Я предполагаю, что это будет работать на стороне сервера. Кажется, я нашел обходное решение, используя таймеры. –

Смежные вопросы