akc42 akc42 - 3 months ago 17
Node.js Question

How do I defne a stream for passing between modules

I have some code designed to send a pdf file back to a web brower. In that code the http server hands over a response stream which I can pipe my pdf ooutput to.

const server = http.createServer((req, res) => {
var doc = new PDFKit({size: 'A4', layout: 'landscape', info: info, margin: 30});
doc.pipe(res);
doc.text('Writing text to document');
doc.end();
});


I now want to use nodemailer to mail the same pdf documents as attachments. So I think I need to do something like this

const Stream = require('stream').Readable;
const stream = new Stream();
transport.sendMail({
to: someone@somewhere,
subject: 'Info You Wanted',
text: 'The data you want is in pdf attachments',
attachments: [{
filename: 'dummy.pdf',
content:stream
}]
});
const doc = new PDFKit({size: 'A4', layout: 'landscape', info: info, margin: 30});
doc.pipe(stream);
doc.text('Writing text to document');
doc.end();


This is where I am confused. Is the above correct? The docs imply I should be extending a Readable, but I am not sure what

Answer

Here is how you do it:

Create a class the extends stream.PassTrough

  const PassThrough = require('stream').PassThrough;
  class Tunnel extends PassThrough {
    constructor() {
      super();
    }
    setHeader() {
      //no op
    }
  }

Create a new instance of this class and pass it to the doc and mail attachments

  const tunnel = new Tunnel();
  transport.sendMail({
  to: someone@somewhere,
  subject: 'Info You Wanted',
  text: 'The data you want is in pdf attachments',
  attachments: [{
    filename: 'dummy.pdf',
    content:tunnel
  }]
 });
 const doc = new PDFKit({size: 'A4', layout: 'landscape', info: info, margin: 30});
 doc.pipe(tunnel);
 doc.text('Writing text to document');
 doc.end();

I had to create a slight variation to the normal PassThrough stream, because the actual pdf processing software through it was replying to an http request and so sets headers and status.