Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converting docx (downloaded from s3) to pdf (uploaded to s3) #255

Open
Ayh4m opened this issue Jan 16, 2023 · 3 comments
Open

Converting docx (downloaded from s3) to pdf (uploaded to s3) #255

Ayh4m opened this issue Jan 16, 2023 · 3 comments

Comments

@Ayh4m
Copy link

Ayh4m commented Jan 16, 2023

Hello guys,

I'm trying to convert a MS Word .docx file (that is being downloaded from S3 bucket) to a pdf one (and upload it to the same location in that S3 bucket).

NOTE: I've tried the layer solution and it did work for me.

I've followed all the mentioned steps:

1- Created my own docker image:

Where my Dockerfile looks like this:

FROM public.ecr.aws/shelf/lambda-libreoffice-base:7.4-node16-x86_64
COPY app.js package.json ${LAMBDA_TASK_ROOT}/
RUN npm install
CMD [ "app.handler" ]

and apps.js looks like this:

const {convertTo, canBeConvertedToPDF} = require('@shelf/aws-lambda-libreoffice');
const fs = require("fs");
const AWS = require("aws-sdk");

const S3_BUCKET = process.env.S3_BUCKET
const WORD_FILE_KEY = process.env.WORD_FILE_KEY
const TMP_DIR = "/tmp"

const s3 = new AWS.S3();


module.exports.handler = async () => {

    console.log(`# Bucket Name: ${S3_BUCKET}`)
    console.log(`# File Name: ${WORD_FILE_KEY}`)
    console.log(`[Initial]: ${getTmpDirContent()}`)

    // Download .docx file from S3 to /tmp
    console.log("# Downloading the .docx file from S3 ...")
    await downloadFileFromS3(WORD_FILE_KEY)
    console.log(`[After Download]: ${getTmpDirContent()}`)

    if (canBeConvertedToPDF(WORD_FILE_KEY)) {
        // Convert .docx to .pdf
        console.log("# Converting .docx file to .pdf file ...")
        const convertedFilePath = convertTo(WORD_FILE_KEY, "pdf");
        console.log(convertedFilePath)
        console.log(`[After Convert]: ${getTmpDirContent()}`)

        // Upload .pdf file to S3
        console.log("# Uploading the .pdf file to S3 ...")
        await uploadFileToS3(convertedFilePath)

        console.log("# Done")
    } else {
        console.log("# Can't be converted tp pdf!")
    }
}

const downloadFileFromS3 = async (fileKey) => {
    try {
        const filePath = `${TMP_DIR}/${fileKey}`
        const params = {
            Bucket: S3_BUCKET,
            Key: fileKey
        }
        const objData = await s3.getObject(params).promise();
        fs.writeFileSync(filePath, objData.Body.toString());
        console.log(`- File ${fileKey} has been downloaded to ${filePath} successfully`);
    } catch (e) {
        throw new Error(`- Download Error: ${e.message}`)
    }
}

const uploadFileToS3 = async (filePath) => {
    try {
        const fileKey = filePath.split(`${TMP_DIR}/`)[1]
        const fileData = fs.readFileSync(filePath)
        const params = {
            Bucket: S3_BUCKET,
            Key: fileKey,
            Body: fileData
        }
        const data = await s3.upload(params).promise();
        console.log(`- Upload successfully at ${data.Location}`);
    } catch (e) {
        throw new Error(`- Upload Error: ${e.message}`)
    }
};

const getTmpDirContent = () => {
    return fs.readdirSync(TMP_DIR)
}

& package.json is the following:

{
  "name": "libreoffice-lambda-container-image",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "@shelf/aws-lambda-libreoffice": "^5.0.1",
    "aws-sdk": "^2.1293.0"
  }
}

2- Pushed it to ECR.

3- Created a Lambda Function:

With the following configurations:
Snag_e5f871b
Snag_e603b86
Snag_e61d495

AND I'm getting the following error:
Snag_e650a4c

Any suggestions?!

@atrudeau-vitall
Copy link

Hey @Ayh4m, I had this same use case and was able to get it working. See the repo here

@fedeotaran
Copy link

I have the same problem, could anyone solve it?

@npahucki
Copy link

For anyone dealing with this specific error: this happens when the log message returned from libreoffice doesn't match a regex return logs.match(/\/tmp\/.+->\s(\/tmp\/.+) using/)[1]; in the library/logs module. This assumes that the log message 1) is in English (the 'using') and 2) that the input and output path both start with /tmp/.

I was bumping into this while testing the code on MacOS where /tmp is a symbolic link to /private/tmp/, so the output path in the messages returned from libreoffice had /private/tmp/ in them and did not match the regex, thus returning null form the match and an error trying to access index 1 of null. I worked around it by monkey patching getConvertedFilePath when testing on MacOS.

It did work just fine for me with no modification while running in the deployed Lambda, however, if someone were to have some locale variables set in their Dockerfile and libreoffice outputs messages in a language other than than English, this would be broken in deployed Lambdas too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants