164 votes

Diriger un flux vers s3.upload ()

Je suis en train de faire usage d'une node.js plugin appelé s3-téléchargement de flux de flux de fichiers très volumineux Amazon S3. Il utilise le multi-parties de l'API et pour la plupart, il fonctionne très bien.

Cependant, ce module est de montrer son âge et j'ai déjà eu à faire les modifications qu'il (l'auteur a retiré de il ainsi). Aujourd'hui j'ai rencontré un autre problème avec Amazon, et je tiens vraiment à prendre de l'auteur de la recommandation et de commencer à utiliser l'officiel aws sdk pour accomplir mes uploads.

MAIS.

Le SDK officiel ne semble pas à l'appui de la tuyauterie s3.upload(). La nature de la s3.télécharger, c'est que vous avez à passer le lisible flux comme un argument pour le S3 constructeur.

J'ai à peu près 120+ code utilisateur modules différents de traitement de fichiers, et ils sont agnostiques à la destination finale de leur sortie. Le moteur de mains un pipeable inscriptible flux de sortie, et ils pipe à elle. Je ne peux pas la main sur eux un AWS.S3 objet et demandez-leur de composer upload() sans ajout de code pour tous les modules. La raison, j'ai utilisé s3-upload-stream a été parce qu'il a appuyé la tuyauterie.

Est-il un moyen de faire aws sdk s3.upload() quelque chose que je peux canaliser le flux?

190voto

Casey Benko Points 859

Enveloppez la fonction S3 upload() avec le flux node.js stream.PassThrough() .

Voici un exemple:

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

182voto

Ahmet Cetin Points 965

Une réponse un peu tardive, cela pourrait aider quelqu'un d'autre avec espoir. Vous pouvez renvoyer à la fois le flux en écriture et la promesse afin que vous puissiez obtenir les données de réponse à la fin du téléchargement.

 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: 'filename.mp4'});
const readStream = fs.createReadStream('/path/to/yourfile.jpg');

readStream.pipe(writeStream);
promise.then(console.log);
 

65voto

taku Points 86

Dans l'acceptation de réponse, la fonction se termine avant que le téléchargement est terminé, et il est donc incorrect. Le code ci-dessous tuyaux correctement lisible à partir d'un flux.

Télécharger référence

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

Vous pouvez également aller plus loin et de sortie des informations de progression à l'aide de ManagedUpload en tant que tel:

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

ManagedUpload de référence

Une liste des événements disponibles

9voto

Solution de script de type:
Cet exemple utilise:

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

Et fonction asynchrone:

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

Appelez cette méthode quelque part comme:

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

5voto

mattdlockyer Points 2098

Si ça aide quelqu'un, j'ai été en mesure de diffuser à partir du client s3 avec succès:

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

Le serverside code suppose req est un objet de flux de données, dans mon cas, il a été envoyé par le client avec des informations sur le fichier défini dans les en-têtes.

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

Oui il rompt la convention, mais si vous regardez l'essentiel c'est beaucoup plus propre que tout autre chose, j'ai trouvé à l'aide de multer, aide-serveur, etc...

+1 pour le pragmatisme et grâce à @SalehenRahman pour son aide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X