Muirik
Muirik

Reputation: 6289

Using base64 Encoding When Passing Data from Node to React to Construct PDF

I am streaming some data from my Node backend to a React frontend, and then am using the streamsaver library to take the stream and save it as a PDF. I was getting the correct number of documents downloaded at the end of the process. However, the pages are blank, suggesting the data is not being encoded properly. So I am trying to use base64 encoding.

My backend code looks like this:

  async getNotesPDFStream(args, session, ctx) {
    try {
      const data = await this.getDataToStream(args, session, ctx);
      fs.writeFileSync("./test.pdf", data); // This test works on the backend - creates a PDF
      const encodedData = btoa(data); // encoding as a base64 string
      const readable = new Readable();
      readable.push(encodedData);
      readable.push(null);
      readable.pipe(ctx.stream);
      return Response.Success("PDF now streaming!");
    } catch (err) {
      console.log("Error 167: ", err);
      return Response.Error("Error retrieving progress notes PDF.", err);
    }
  }

And on the React frontend I do this:

  let buffer = '';
   dataStream.on('data', (data) => {
     buffer += data;
  });

  dataStream.on('end', () => {
    console.log('STREAM FINISHED');
    const fileStream = streamSaver.createWriteStream('notes.pdf');

    const decodedData = atob(buffer); // Decode the final buffer
    console.log('decodedData: ', decodedData);

    const pdfBlob = new Blob([decodedData], { type: 'application/pdf' });
    const readableStream = pdfBlob.stream();

    if (window.WritableStream && readableStream.pipeTo) {
      return readableStream
        .pipeTo(fileStream)
        .then(() => console.log('Done writing'));
    }
    // Write (pipe) manually
    const writer = fileStream.getWriter();
    const reader = readableStream.getReader();
    const pump = () =>
      reader
        .read()
        .then(res =>
          res.done ? writer.close() : writer.write(res.value).then(pump)
        );
    pump();

After trying this I have the correct number of pages downloaded with the PDF document, but the pages are still blank. What am I missing here? How can I ensure this is encoded properly?

By the way, I tried using some basic html and passed that in the same way, using the same encoding methods, and it reconstructed the html correctly. Is there something specifically about constructing as a PDF that I need to be aware of?

Upvotes: 2

Views: 356

Answers (1)

Muirik
Muirik

Reputation: 6289

In the end I realized I was making it more complicated than necessary. Using the writer.write() functionality I was able to come up with this terse working solution:

  dataStream.on('data', (data) => {
    writer.write(data) // should be a Uint8Array
  })

  dataStream.on('end', () => {
    console.log('STREAM FINISHED');
    writer.close();
  });

Upvotes: 1

Related Questions