Канал Node PDFKit для нескольких целей

У меня возникла проблема, когда мне нужно pipe() отправить созданный документ нескольким целям, в моем случае - ответу HTTP и вложению электронной почты, используя node-mailer. После первого использования во вложении к электронному письму ничего не передается в ответ (при вызове из клиента PDF имеет 0 байт).

Ответный контроллер:

const doc = await createPdf(course.name, lastRecordDate, ctx);   

// Send a notificiation email with attachment
if (query.hasOwnProperty('sendEmail') && query.sendEmail === 'true') {
  await sendNotificationEmail(doc, course, ctx);   
}

doc.pipe(res);
res.contentType('application/pdf');

Функция отправки электронного письма:

async function sendNotificationEmail(doc: any, course: Course, ctx: Context) {
  const attachment = {
    filename: `${course.name}-certificate.pdf`,
    contentType: 'application/pdf',
    content: doc
  };
  return SMTPSendTemplateWithAttachments(
    ctx,
    ['[email protected]'],
    `${course.name}`,
    'en-report-created',
    {
      firstName: ctx.user.firstName,
      courseName: course.name
    },
    [attachment]
  );
}

Если я удаляю функцию отправки электронного письма, PDF-файл обычно передается в ответ, и я могу загрузить его с клиента.

Я пытался найти способ клонировать поток (насколько я знаю, документ PDFKit является потоком), но безуспешно.

Любое решение будет действительно полезным.


person AndrejH    schedule 18.07.2019    source источник


Ответы (1)


Я решил проблему, используя два потока PassThrough, два из которых я передал PDFKitdocument Stream, а затем в событии data я записал chunks в два отдельных буфера. В событии end я отправляю данные по электронной почте, создаю новый поток PassThrough и передаю его в ответ.

Вот код.

// Both PassThrough streams are defined before in order to use them in the createPdf function
streamCopy1 = new PassThrough();
streamCopy2 = new PassThrough();

const buffer1 = [];
const buffer2 = [];

streamCopy1
  .on('data', (chunk) => {
    buffer1.push(chunk);
  })
  .on('end', () => {
    const bufferFinished = Buffer.concat(buffer1);
    if (query.hasOwnProperty('sendEmail') && query.sendEmail === 'true') {
      sendNotificationEmail(bufferFinished, course, ctx);
    }
  });

streamCopy2
  .on('data', (chunk) => {
    buffer2.push(chunk);
  })
  .on('end', () => {
    const bufferFinished = Buffer.concat(buffer2);
    const stream = new PassThrough();
    stream.push(bufferFinished);
    stream.end();
    stream.pipe(res);
    res.contentType('application/pdf');
  });

Функция для создания PDF.

// function declaration
const doc = new pdfDocument();
doc.pipe(streamCopy1).pipe(streamCopy2);
// rest of the code

Решение на самом деле не самое приятное, любые предложения очень приветствуются.

person AndrejH    schedule 22.07.2019