Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using promises with PDFMake on Firebase Cloud Functions

I am using PDFMake (a variant of PDFKit) to generate PDFs on Firebase Cloud Functions using a realtime database trigger. The function gets all relevant data from the database and then passes it to the function that is supposed to generate the PDF.

All this is done using Promises. Everything works fine until the point where the PDF is actually generated.

Here's the code in my main event listener:

exports.handler = (admin, event, storage) => {
  const quotationData = event.data.val();
  // We must return a Promise when performing async tasks inside Functions
  // Eg: Writing to realtime db
  const companyId = event.params.companyId;
  settings.getCompanyProfile(admin, companyId)
  .then((profile) => {
    return quotPdfHelper.generatePDF(fonts, profile, quotationData, storage);
  })
  .then(() => {
    console.log('Generation Successful. Pass for email');
  })
  .catch((err) => {
    console.log(`Error: ${err}`);
  });
};

To generate the PDF, here's my code:

exports.generatePDF = (fonts, companyInfo, quotationData, storage) => {
  const printer = new PdfPrinter(fonts);
  const docDefinition = {
    content: [
      {
        text: [
          {
            text: `${companyInfo.title}\n`,
            style: 'companyHeader',
          },
          `${companyInfo.addr_line1}, ${companyInfo.addr_line2}\n`,
          `${companyInfo.city} (${companyInfo.state}) - INDIA\n`,
          `Email: ${companyInfo.email} • Web: ${companyInfo.website}\n`,
          `Phone: ${companyInfo.phone}\n`,
          `GSTIN: ${companyInfo.gst_registration_number}  • PAN: AARFK6552G\n`,
        ],
        style: 'body',
         //absolutePosition: {x: 20, y: 45}
      },
    ],
    styles: {
      companyHeader: {
        fontSize: 18,
        bold: true,
      },
      body: {
        fontSize: 10,
      },
    },
    pageMargins: 20,
  };
  return new Promise((resolve, reject) => {
    // const bucket = storage.bucket(`${PROJECT_ID}.appspot.com`);
    // const filename = `${Date.now()}-quotation.pdf`;
    // const file = bucket.file(filename);
    // const stream = file.createWriteStream({ resumable: false });
    const pdfDoc = printer.createPdfKitDocument(docDefinition);
    // pdfDoc.pipe(stream);

    const chunks = [];
    let result = null;

    pdfDoc.on('data', (chunk) => {
      chunks.push(chunk);
    });
    pdfDoc.on('error', (err) => {
      reject(err);
    });
    pdfDoc.on('end', () => {
      result = Buffer.concat(chunks);
      resolve(result);
    });
    pdfDoc.end();
  });
};

What could be wrong here that is preventing the promise and thereby the quotation code to be executed as intended?

On firebase log, all I see is Function execution took 3288 ms, finished with status: 'ok'

like image 357
Gaurav Wadhwani Avatar asked Nov 06 '17 18:11

Gaurav Wadhwani


1 Answers

Based on the execution time and lack of errors, it looks like you're successfully creating the buffer for the PDF but you're not actually returning it from the function.

.then((profile) => {
  return quotPdfHelper.generatePDF(fonts, profile, quotationData, storage);
})
.then(() => {
  console.log('Generation Successful. Pass for email');
})

In the code above, you're passing the result to the next then block, but then returning undefined from that block. The end result of this Promise chain will be undefined. To pass the result through, you'd want to return it at the end of the Promise chain:

.then((profile) => {
  return quotPdfHelper.generatePDF(fonts, profile, quotationData, storage);
})
.then(buffer => {
  console.log('Generation Successful. Pass for email');
  return buffer;
})
like image 164
rrowland Avatar answered Sep 30 '22 08:09

rrowland