2016-05-20 3 views
22

Я использую плагин node.js под названием s3-upload-stream, чтобы передать очень большие файлы Amazon S3. Он использует многопроцессорный API и по большей части работает очень хорошо.Pipe the stream to s3.upload()

Однако этот модуль показывает свой возраст, и я уже должен был внести в него изменения (автор тоже не рекомендовал его). Сегодня я столкнулся с другим вопросом с Amazon, и мне бы очень хотелось взять рекомендацию автора и начать использовать официальный aws-sdk для выполнения моих загрузок.

НО.

Официальный SDK, похоже, не поддерживает трубопроводы до s3.upload(). Характер s3.upload состоит в том, что вы должны передать читаемый поток в качестве аргумента в конструктор S3.

У меня есть примерно 120 модулей кода пользователя, которые выполняют различные обработки файлов, и они не зависят от конечного пункта назначения их вывода. Двигатель передает им доступный для записи выходной поток, и они подключаются к нему. Я не могу передать им объект AWS.S3 и попросить их называть его upload() без добавления кода ко всем модулям. Причина, по которой я использовал s3-upload-stream, состояла в том, что она поддерживала трубопроводы.

Есть ли способ сделать aws-sdk s3.upload() что-то, что я могу передать потоку?

ответ

40

Оберните upload() функция S3 с node.js stream.PassThrough() потока.

Вот пример:

inputStream 
    .pipe(uploadFromStream(s3)); 

function uploadFromStream(s3) { 
    var pass = new stream.PassThrough(); 

    var params = {Bucket: BUCKET, Key: KEY, Body: pass}; 
    s3.upload(params, function(err, data) { 
    console.log(err, data); 
    }); 

    return pass; 
} 
+1

Великими, это решить мою очень уродливый хак = -) Может вы объясните, что делает stream.PassThrough() на самом деле? – mraxus

+2

Ваш поток PassThrough закрывается, когда вы это делаете? У меня есть чертовски время, пропедевщее закрытие в s3.upload, чтобы попасть в мой поток PassThrough. – cr125rider

+0

Это работает, спасибо! – thewoolleyman

-2

Если вы знаете размер потока, который вы можете использовать minio-js, чтобы загрузить поток, как это:

s3Client.putObject('my-bucketname', 'my-objectname.ogg', stream, size, 'audio/ogg', function(e) { 
    if (e) { 
     return console.log(e) 
    } 
    console.log("Successfully uploaded the stream") 
    }) 
1

Если это поможет кому я был в состоянии потока от клиента успешно s3:

https://gist.github.com/mattlockyer/532291b6194f6d9ca40cb82564db9d2a

Код серверной предполагает req является объектом потока, в моем случае он был отправлен от клиента с информацией о файле, установленной в заголовках.

const fileUploadStream = (req, res) => { 
    //get "body" args from header 
    const { id, fn } = JSON.parse(req.get('body')); 
    const Key = id + '/' + fn; //upload to s3 folder "id" with filename === fn 
    const params = { 
    Key, 
    Bucket: bucketName, //set somewhere 
    Body: req, //req is a stream 
    }; 
    s3.upload(params, (err, data) => { 
    if (err) { 
     res.send('Error Uploading Data: ' + JSON.stringify(err) + '\n' + JSON.stringify(err.stack)); 
    } else { 
     res.send(Key); 
    } 
    }); 
}; 

Да она нарушает соглашение, но если вы посмотрите на суть это гораздо чище, чем все остальное я нашел с помощью multer, Busboy и т.д ...

+1 к прагматизму и благодаря @SalehenRahman за помощь ,

+0

multer , busboy handle multipart/form-data uploads. req как поток работает, когда клиент отправляет буфер как тело из XMLHttpRequest. –

6

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

Upload reference

async function uploadReadableStream(stream) { 
    const params = {Bucket: bucket, Key: key, Body: stream}; 
    return s3.upload(params).promise(); 
} 

async function upload() { 
    const readable = getSomeReadableStream(); 
    const results = await uploadReadableStream(readable); 
    console.log('upload complete', results); 
} 

Вы также можете пойти на шаг дальше и инфомацию прогресса с использованием ManagedUpload как таковые:

const manager = s3.upload(params); 
manager.on('httpUploadProgress', (progress) => { 
    console.log('progress', progress) // { loaded: 4915, total: 192915, part: 1, key: 'foo.jpg' } 
}); 

ManagedUpload reference

A list of available events

+1

aws-sdk теперь предлагает обещания, встроенные в 2.3.0+, поэтому вам больше не нужно их поднимать. s3.upload (params) .promise(). then (data => data) .catch (error => error); – DBrown

+1

@DBrown Спасибо за указатель! Я обновил ответ, соответственно. – tsuz

+0

@tsuz, пытается реализовать свое решение, дать мне эрро r: 'TypeError: dest.on не является функцией', любая идея почему? – FireBrand