2017-06-20 4 views
5

Je Spawn un processus enfant comme ceci:Transformer flux préfixer chaîne à chaque ligne

const n = cp.spawn('bash'); 

n.stdout.pipe(process.stdout); 
n.stderr.pipe(process.stderr); 

Je cherche une transformation flux afin que je puisse préfixer quelque chose comme « [processus enfant] » au début de chaque ligne de l'enfant, donc je sais que le stdio vient de l'enfant par rapport au processus parent.

Il ressemblerait à ceci:

const getTransformPrepender = function() : Transform { 
    return ... 
} 

n.stdout.pipe(getTransformPrepender('[child]')).pipe(process.stdout); 
n.stderr.pipe(getTransformPrepender('[child]')).pipe(process.stderr); 

que quelqu'un sait s'il y a un package existant transform comme ceci ou comment écrire un?

J'ai ceci:

import * as stream from 'stream'; 


export default function(pre: string){ 

    let saved = ''; 

    return new stream.Transform({ 

    transform(chunk, encoding, cb) { 

     cb(null, String(pre) + String(chunk)); 
    }, 

    flush(cb) { 
     this.push(saved); 
     cb(); 
    } 

    }); 

} 

mais je crains que cela ne fonctionnera pas dans les cas de bord - où un morceau rafale ne peut pas comprendre une ligne entière (pour les lignes très longues).

Il semble que la réponse est ici: https://strongloop.com/strongblog/practical-examples-of-the-new-node-js-streams-api/

mais avec ce supplément: https://twitter.com/the1mills/status/886340747275812865

Répondre

5

Il y a au total trois cas que vous devez gérer correctement:

  • Un morceau unique représentant une ligne entière
  • Un seul bloc représentant plusieurs lignes
  • Un seul bloc représentant seulement une partie de la ligne

Voici une description de l'algorithme pour résoudre les trois situations

  1. Recevez un bloc de données
  2. Scannez le morceau pour les nouvelles lignes
  3. Dès qu'une nouvelle ligne se trouve, prendre tout avant qu'il (y compris le saut de ligne) et l'envoyer comme une seule ligne avec les modifications dont vous avez besoin
  4. Répétez jusqu'à ce que le morceau entier a été traitée (aucune donnée restante) jusqu'à ce qu'aucun retour à la ligne supplémentaire n'a été trouvé (certaines données reste, enregistrez-le pour plus tard)

et voici une mise en œuvre effective des descriptions des raisons pour lesquelles il est nécessaire etc.

Veuillez noter que pour des raisons de performances, je ne convertis pas les Buffers en chaînes JS classiques.

const { Transform } = require('stream') 

const prefix = Buffer.from('[worker]: ') 

const prepender = new Transform({ 
    transform(chunk, encoding, done) { 
    this._rest = this._rest && this._rest.length 
     ? Buffer.concat([this._rest, chunk]) 
     : chunk 

    let index 

    // As long as we keep finding newlines, keep making slices of the buffer and push them to the 
    // readable side of the transform stream 
    while ((index = this._rest.indexOf('\n')) !== -1) { 
     // The `end` parameter is non-inclusive, so increase it to include the newline we found 
     const line = this._rest.slice(0, ++index) 
     // `start` is inclusive, but we are already one char ahead of the newline -> all good 
     this._rest = this._rest.slice(index) 
     // We have a single line here! Prepend the string we want 
     this.push(Buffer.concat([prefix, line])) 
    } 

    return void done() 
    }, 

    // Called before the end of the input so we can handle any remaining 
    // data that we have saved 
    flush(done) { 
    // If we have any remaining data in the cache, send it out 
    if (this._rest && this._rest.length) { 
     return void done(null, Buffer.concat([prefix, this._rest]) 
    } 
    }, 
}) 

process.stdin.pipe(prepender).pipe(process.stdout) 
2

Ce travail est en cours:

https://github.com/ORESoftware/prepend-transform

, mais il est conçu pour résoudre le problème à portée de main comme suit:

import pt from 'prepend-transform'; 
import * as cp from 'child_process'; 

const n = cp.spawn('bash'); 

n.stdout.pipe(pt('[child stdout]')).pipe(process.stdout); 
n.stderr.pipe(pt('[child stderr]')).pipe(process.stderr); 
+0

mais ce n'est pas encore terminé, car il ne peut pas gérer les longues lignes qui représentent plusieurs appels ('data'). –

+0

cette implémentation n'est pas complète et j'ai besoin d'aide pour la corriger. –

+0

Je pense que cela a la réponse - https://strongloop.com/strongblog/practical-examples-of-the-new-node-js-streams-api/ –