এস 3 আপলোড স্ট্রিমের পাইপ করুন ()


95

আমি বর্তমানে অ্যামাজন এস 3 - তে খুব বড় ফাইল স্ট্রিম করতে এস-আপলোড-স্ট্রিম নামে একটি নোড.জেএস প্লাগইন ব্যবহার করছি । এটি মাল্টিপার্ট এপিআই ব্যবহার করে এবং বেশিরভাগ অংশের জন্য এটি খুব ভালভাবে কাজ করে।

যাইহোক, এই মডিউলটি তার বয়স দেখাচ্ছে এবং আমাকে ইতিমধ্যে এটিতে সংশোধন করতে হয়েছিল (লেখক এটিও অবনতি করেছেন)। আজ আমি অ্যামাজনের সাথে অন্য একটি ইস্যুতে ছড়িয়ে পড়েছি এবং আমি সত্যিই লেখকের সুপারিশ নিতে এবং আমার আপলোডগুলি সম্পাদন করতে অফিসিয়াল অ্যাডস-এসডিকে ব্যবহার শুরু করতে চাই।

কিন্তু

অফিসিয়াল এসডিকে পাইপিং সমর্থন করে বলে মনে হচ্ছে না s3.upload()। S3.upload এর প্রকৃতি হ'ল আপনাকে S3 কনস্ট্রাক্টরের পক্ষে যুক্তি হিসাবে পাঠযোগ্য স্ট্রিমটি পাস করতে হবে।

আমার কাছে প্রায় 120+ ব্যবহারকারীর কোড মডিউল রয়েছে যা বিভিন্ন ফাইল প্রসেসিং করে এবং এগুলি আউটপুটটির চূড়ান্ত গন্তব্যস্থলে অজ্ঞেয়াদি। ইঞ্জিন তাদের একটি পাইপযোগ্য লিখনযোগ্য আউটপুট স্ট্রিম দেয় এবং তারা এটিতে পাইপ দেয়। আমি তাদের কোনও AWS.S3বস্তু হস্তান্তর করতে পারি না এবং upload()সমস্ত মডিউলগুলিতে কোড যুক্ত না করে এটিকে ফোন করতে বলি । আমি যে কারণটি ব্যবহার করেছি তা s3-upload-streamহ'ল এটি পাইপিং সমর্থন করে।

s3.upload()স্ট্রিমটি পাইপ করতে পারে এমন কোনও উপায়-এসডিকে করার কী উপায় আছে?

উত্তর:


137

upload()নোড.জেএস stream.PassThrough()স্ট্রিমের সাথে এস 3 ফাংশনটি মোড়ুন ।

এখানে একটি উদাহরণ:

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;
}

4
দুর্দান্ত, এটি আমার খুব কুৎসিত হ্যাকটি সমাধান করেছে - - - আপনি কী স্ট্রিম.পাসথ্রু () আসলে কী তা ব্যাখ্যা করতে পারেন?
মারাকাস

6
আপনি যখন এটি করেন তখন আপনার পাসথ্রো স্ট্রিমটি কি বন্ধ হয়? আমার পাসথ্র্র স্ট্রিমটি হিট করতে s3.upload এর কাছাকাছি অবস্থান বন্ধ করার জন্য আমার একটি সময় আছে।
চার 43

7
আপলোড করা ফাইলটির আকার 0 বাইট। যদি আমি উত্স স্ট্রিম থেকে ফাইল সিস্টেমে একই ডেটা পাইপ করি তবে সমস্ত ভাল কাজ করে। কোন ধারণা?
রাডার 155

4
একটি পাসথ্রু স্ট্রিম এতে লিখিত বাইট গ্রহণ করে সেগুলি আউটপুট দেয়। এটি আপনাকে এমন একটি লিখনযোগ্য স্রোত ফিরিয়ে দিতে দেয় যা আউস-এসডিকে আপনি এটি লিখতে পড়তে পঠিত। আমি s3.upload () থেকে প্রতিক্রিয়াটির বিষয়টিও ফিরিয়ে দেব কারণ অন্যথায় আপনি আপলোড সম্পূর্ণরূপে নিশ্চিত করতে পারবেন না।
পুনরায় সংযোগ করুন

4
এটি কি কেবল পাঠযোগ্য স্ট্রিমটি বডি তে পাঠানোর মতো নয়, তবে আরও কোড সহ? এডাব্লুএস এসডিকে এখনও পাসথ্রো স্ট্রিমে রিড () কল করতে চলেছে যাতে এস 3-এর সমস্ত উপায় নেই true পার্থক্যটি হ'ল মাঝখানে একটি অতিরিক্ত স্রোত।
শ্যাডোচেজার

96

কিছুটা দেরি করে দেওয়া উত্তর, এটি আশাবাদী অন্য কাউকে সাহায্য করতে পারে। আপনি লেখার মতো স্ট্রিম এবং প্রতিশ্রুতি উভয়ই ফিরিয়ে দিতে পারেন, তাই আপলোড শেষ হয়ে গেলে আপনি প্রতিক্রিয়া ডেটা পেতে পারেন।

const AWS = require('aws-sdk');
const stream = require('stream');

const uploadStream = ({ Bucket, Key }) => {
  const s3 = new AWS.S3();
  const pass = new stream.PassThrough();
  return {
    writeStream: pass,
    promise: s3.upload({ Bucket, Key, Body: pass }).promise(),
  };
}

এবং আপনি নিম্নলিখিত হিসাবে ফাংশন ব্যবহার করতে পারেন:

const { writeStream, promise } = uploadStream({Bucket: 'yourbucket', Key: 'yourfile.mp4'});
const readStream = fs.createReadStream('/path/to/yourfile.mp4');

const pipeline = readStream.pipe(writeStream);

এখন আপনি হয় প্রতিশ্রুতি পরীক্ষা করতে পারেন:

promise.then(() => {
  console.log('upload completed successfully');
}).catch((err) => {
  console.log('upload failed.', err.message);
});

বা stream.pipe()রিটার্ন স্ট্রিম হিসাবে W রাইটিং, গন্তব্য (উপরে রাইটস্ট্রিম ভেরিয়েবল), পাইপের একটি শৃঙ্খলার অনুমতি দেয় আমরা এর ইভেন্টগুলিও ব্যবহার করতে পারি:

 pipeline.on('close', () => {
   console.log('upload successful');
 });
 pipeline.on('error', (err) => {
   console.log('upload failed', err.message)
 });

এটি দুর্দান্ত দেখাচ্ছে, তবে আমার পক্ষে আমি এই ত্রুটিটি পাচ্ছি stackoverflow.com/questions/62330721/…
আর্কো Voltaico

শুধু আপনার প্রশ্নের জবাব। আশা করি এটা সাহায্য করবে.
আহমেট কেটিন

49

গৃহীত উত্তরে, আপলোডটি সম্পূর্ণ হওয়ার আগে ফাংশনটি শেষ হয় এবং এভাবে ভুল হয়। নীচের কোডটি পঠনযোগ্য স্ট্রিম থেকে সঠিকভাবে পাইপগুলি।

রেফারেন্স আপলোড করুন

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' }
});

পরিচালিত আপলোড রেফারেন্স

উপলভ্য ইভেন্টগুলির একটি তালিকা


4
aws-sdk এখন ২.৩.০+ এর মধ্যে নির্মিত প্রতিশ্রুতি দেয়, যাতে আপনার আর সেগুলি তুলতে হবে না। s3.upload (params)। প্রোমাইজ ()। তারপর (ডেটা => ডেটা)। ক্যাচ (ত্রুটি => ত্রুটি);
DBrown

4
@DBrown পয়েন্টার জন্য ধন্যবাদ! আমি সেই অনুযায়ী উত্তর আপডেট করেছি।
tsuz

4
@tsuz, আপনার সমাধানটি প্রয়োগের চেষ্টা আমাকে একটি ত্রুটি দেয়:, TypeError: dest.on is not a functionকোনও ধারণা কেন?
ফায়ারব্র্যান্ড

কী dest.on? আপনি একটি উদাহরণ দেখাতে পারেন? @ ফায়ারব্র্যান্ড
tsuz

9
এটি বলেছে গৃহীত উত্তরটি অসম্পূর্ণ তবে এটি @ ওয়ার্পের আপডেট হওয়া পোস্টে উল্লিখিত হিসাবে s3.upload এ পাইপিংয়ের সাথে কাজ করে না। এই উত্তরটি অন্য কোনও পাইপের আউটপুট নিতে আপডেট করা হলে এটি খুব সহায়ক হবে!
ম্যাটডাব্লু

6

উত্তরগুলির কোনওটিই আমার পক্ষে কার্যকর হয়নি কারণ আমি চেয়েছিলাম:

  • পাইপ s3.upload()
  • ফলাফলটি s3.upload()অন্য স্ট্রিমে পাইপ করুন

গৃহীত উত্তরটি উত্তর দেয় না। অন্যরা প্রতিশ্রুত এপিআইয়ের উপর নির্ভর করে যা স্ট্রিম পাইপগুলির সাথে কাজ করার সময় কাজ করা জটিল umbers

এটি আমার গৃহীত উত্তরের পরিবর্তন।

const s3 = new S3();

function writeToS3({Key, Bucket}) {
  const Body = new stream.PassThrough();

  s3.upload({
    Body,
    Key,
    Bucket: process.env.adpBucket
  })
   .on('httpUploadProgress', progress => {
       console.log('progress', progress);
   })
   .send((err, data) => {
     if (err) {
       Body.destroy(err);
     } else {
       console.log(`File uploaded and available at ${data.Location}`);
       Body.destroy();
     }
  });

  return Body;
}

const pipeline = myReadableStream.pipe(writeToS3({Key, Bucket});

pipeline.on('close', () => {
  // upload finished, do something else
})
pipeline.on('error', () => {
  // upload wasn't successful. Handle it
})


দেখতে দুর্দান্ত
লাগছে

5

টাইপ স্ক্রিপ্ট সমাধান:
এই উদাহরণটি ব্যবহার করে:

import * as AWS from "aws-sdk";
import * as fsExtra from "fs-extra";
import * as zlib from "zlib";
import * as stream from "stream";

এবং অ্যাসিঙ্ক ফাংশন:

public async saveFile(filePath: string, s3Bucket: AWS.S3, key: string, bucketName: string): Promise<boolean> { 

         const uploadStream = (S3: AWS.S3, Bucket: string, Key: string) => {
            const passT = new stream.PassThrough();
            return {
              writeStream: passT,
              promise: S3.upload({ Bucket, Key, Body: passT }).promise(),
            };
          };
        const { writeStream, promise } = uploadStream(s3Bucket, bucketName, key);
        fsExtra.createReadStream(filePath).pipe(writeStream);     //  NOTE: Addition You can compress to zip by  .pipe(zlib.createGzip()).pipe(writeStream)
        let output = true;
        await promise.catch((reason)=> { output = false; console.log(reason);});
        return output;
}

এই পদ্ধতিটি কোথাও কল করুন:

let result = await saveFileToS3(testFilePath, someS3Bucket, someKey, someBucketName);

4

উপরের সর্বাধিক গ্রহণযোগ্য উত্তরে নোট করার জন্য এখানে জিনিসটি হ'ল: আপনি যদি পাইপ ব্যবহার করে থাকেন তবে আপনাকে ফাংশনে পাসটি ফিরিয়ে আনতে হবে,

fs.createReadStream(<filePath>).pipe(anyUploadFunction())

function anyUploadFunction () { 
 let pass = new stream.PassThrough();
 return pass // <- Returning this pass is important for the stream to understand where it needs to write to.
}

অন্যথায় এটি ত্রুটি না ছড়িয়ে নিঃশব্দে পরবর্তী দিকে চলে যাবে বা TypeError: dest.on is not a functionআপনি কীভাবে ফাংশনটি লিখেছেন তার উপর নির্ভর করে একটি ত্রুটি নিক্ষেপ করবে


3

এটি যদি কাউকে সহায়তা করে তবে আমি ক্লায়েন্ট থেকে সফলভাবে এস 3 এ স্ট্রিম করতে সক্ষম হয়েছি:

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);
    }
  });
};

হ্যাঁ এটি কনভেনশনটি ভেঙে দেয় তবে আপনি যদি সংক্ষেপে তাকান এটি মাল্টার, বাসবয় ইত্যাদি ব্যবহার করে পাওয়া অন্য যে কোনও কিছুর চেয়ে অনেক পরিষ্কার clean

বাস্তববাদের জন্য +1 এবং তাঁর সহায়তার জন্য @ স্যালেনআরহমানকে ধন্যবাদ জানাই।


মাল্টার, বাসবয় হ্যান্ডেল মাল্টিপার্ট / ফর্ম-ডেটা আপলোড। XMLHttpRequest থেকে ক্লায়েন্ট যখন শরীরের হিসাবে বাফার প্রেরণ করে তখন স্ট্রিম হিসাবে রেক কাজ করে।
আন্দ্রে ওয়ার্ল্যাং

পরিষ্কার করার জন্য, আপলোডটি ক্লায়েন্টের ঠিক নয়, শেষ প্রান্ত থেকে করা হচ্ছে?
numX

হ্যাঁ এটি প্রবাহটিকে "পাইপিং" করছে ব্যাকএন্ডে, তবে এটি একটি
সীমান্ত

3

যারা অভিযোগ করে তাদের জন্য যে তারা যখন এস 3 এপিআই আপলোড ফাংশনটি ব্যবহার করে এবং একটি শূন্য বাইট ফাইলটি এস 3 (@ রাডার 155 এবং @ গাবো) এ শেষ হয় - আমারও এই সমস্যা হয়েছিল।

দ্বিতীয় পাসথ্রো স্ট্রিম তৈরি করুন এবং প্রথম থেকে দ্বিতীয়টিতে সমস্ত ডেটা পাইপ করুন এবং সেই দ্বিতীয়টি রেফারেন্সটি এস 3 এ পাস করুন। আপনি এটি বেশ কয়েকটি উপায়ে করতে পারেন - সম্ভবত একটি নোংরা উপায় হ'ল প্রথম স্ট্রিমের "ডেটা" ইভেন্টটি শুনতে হবে এবং তারপরে একই স্ট্রিমটিকে দ্বিতীয় স্ট্রিমে লিখতে হবে - একইভাবে "শেষ" ইভেন্টের জন্য - কেবল কল করুন দ্বিতীয় প্রবাহে শেষ ফাংশন। এটি আউজ এপি, নোডের সংস্করণ বা অন্য কোনও সমস্যার মধ্যে কোনও বাগ কিনা তা আমার কোনও ধারণা নেই - তবে এটি আমার জন্য ইস্যুটি নিয়ে কাজ করেছিল।

এটি দেখতে কেমন হতে পারে তা এখানে:

var PassThroughStream = require('stream').PassThrough;
var srcStream = new PassThroughStream();

var rstream = fs.createReadStream('Learning/stocktest.json');
var sameStream = rstream.pipe(srcStream);
// interesting note: (srcStream == sameStream) at this point
var destStream = new PassThroughStream();
// call your s3.upload function here - passing in the destStream as the Body parameter
srcStream.on('data', function (chunk) {
    destStream.write(chunk);
});

srcStream.on('end', function () {
    dataStream.end();
});

এটি আসলে আমার পক্ষে কাজ করেছিল। এস 3 আপলোড ফাংশনটি যখনই কোনও মাল্টিপার্ট আপলোড ব্যবহৃত হত নিঃশব্দে কেবল "মারা" যায় তবে আপনার সমাধানটি ব্যবহার করার সময় এটি দুর্দান্ত (!) কাজ করে। ধন্যবাদ! :)
jhdrn

দ্বিতীয় প্রবাহটির প্রয়োজন কেন আপনি কিছু তথ্য দিতে পারেন?
noob7

2

অন্যান্য উত্তরগুলি অনুসরণ করে এবং নোড.জেএস এর জন্য সর্বশেষতম এডাব্লুএস এসডিকে ব্যবহার করে, এস 3 আপলোড () ফাংশনটি একটি স্ট্রিম গ্রহণ করে, প্রতীক্ষিত বাক্য গঠন এবং এস 3 এর প্রতিশ্রুতি ব্যবহার করে একটি আরও পরিষ্কার এবং সহজ সমাধান রয়েছে:

var model = await s3Client.upload({
    Bucket : bucket,
    Key : key,
    ContentType : yourContentType,
    Body : fs.createReadStream(path-to-file)
}).promise();

0

আমি KnexJS ব্যবহার করছি এবং তাদের স্ট্রিমিং এপিআই ব্যবহার করে একটি সমস্যা হয়েছে। আমি অবশেষে এটি স্থির করে নিলাম, আশা করি নীচেরগুলি কাউকে সহায়তা করবে

const knexStream = knex.select('*').from('my_table').stream();
const passThroughStream = new stream.PassThrough();

knexStream.on('data', (chunk) => passThroughStream.write(JSON.stringify(chunk) + '\n'));
knexStream.on('end', () => passThroughStream.end());

const uploadResult = await s3
  .upload({
    Bucket: 'my-bucket',
    Key: 'stream-test.txt',
    Body: passThroughStream
  })
  .promise();

-3

আপনি যদি স্ট্রিমের আকার জানেন তবে আপনি স্ট্রিমটি এভাবে আপলোড করতে মিনিও-জেএস ব্যবহার করতে পারেন :

  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")
  })
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.