node.js Aws Lambda: getObject to base64

Viewed 6874

I have modified the zip function from here https://dzone.com/articles/serverless-zipchamp-update-your-zip-files-in-s3-al because it can only zip text and not zip images.

The Problem occurs in the function base64_encode at the end of the code. I can write the base64 string to the console but can not give it back to the calling function.

Any help is welcome.

let AWS = require('aws-sdk');
let JSZip = require("jszip");
let fs = require("fs");
const s3 = new AWS.S3();
let thebase='';


exports.handler = function (event, context, callback) {
    let myzip = event.zip;
    let modified = 0, removed = 0;
    let mypath = event.path;
    let mynewname = event.newname;
    let filename = event.filename;

 //get Zip file
    s3.getObject({
        'Bucket': "tripmasterdata",
        'Key': event.path+'/'+myzip,
       
    }).promise()
        .then(data => {
            let jszip = new JSZip();
            jszip.loadAsync(data.Body).then(zip => {
                // add or remove file
                if (filename !== '') {
                      //here I get the Image to be stored in the zip as base64 encoded string
                      thebase = base64_encode(mypath,filename,thebase);
                      console.log('AD:'+thebase); //<- this is always empty, WHY????
                      zip.file(mynewname, thebase, {createFolders: false,compression: "STORE",base64: true});
                      modified++;
                } else {
                      console.log(`Remove ${filename}`);
                      zip.remove(filename);
                      removed++;
                }

                let tmpzip = `/tmp/${myzip}`
                let tmpPath = `${event.path}`
                //Generating the zip
                console.log(`Writing to temp file ${tmpzip}`);
                zip.generateNodeStream({ streamFiles: true })
                    .pipe(fs.createWriteStream(tmpzip))
                    .on('error', err => callback(err))
                    .on('finish', function () {
                        console.log(`Uploading to ${event.path}`);
                        s3.putObject({
                            "Body": fs.createReadStream(tmpzip),
                            "Bucket": "xxx/"+tmpPath,
                            "Key": myzip,
                            "Metadata": {
                                "Content-Length": String(fs.statSync(tmpzip).size)
                            }
                        })
                            .promise()
                            .then(data => {
                                console.log(`Successfully uploaded ${event.path}`);
                                callback(null, {
                                    modified: modified,
                                    removed: removed
                                });
                            })
                            .catch(err => {
                                callback(err);
                            });
                    });
            })
                .catch(err => {
                    callback(err);
                });
        })
        .catch(err => {
            callback(err);
        });
}
//function that should return my base64 encoded image
function base64_encode(path,file,thebase) {
    var leKey = path+'/'+file;
    var params = {
    'Bucket': "xxx",
        'Key': leKey
    }
   s3.getObject(params, function(error, data) {
        console.log('error: '+error);
      }).promise().then(data => {
         thebase = data.Body.toString('base64');
         console.log('thebase: '+thebase); //<- here I see the base64 encoded string
         return thebase; //<- does not return thebase
       });
      return thebase; //<- does not return thebase
}

1 Answers

This is a promise related issue the last call in the function 'return thebase;' will most likely return undefined as the promise has not resolved yet. when the function returns. I find it useful to use the keywords async and await this really reduces the code into a lot more readable format (it flattens the code a lot).

function base64_encode(path,file,thebase) {
  var leKey = path+'/'+file;
  var params = {
    'Bucket': "xxx",
    'Key': leKey
  }
  return s3.getObject(params).promise();
}

Then in the main function you want to handle the promise with a .then()

If you were using async / await it would look like the following:

async function base64_encode(path,file,thebase) {
  var leKey = path+'/'+file;
  var params = {
    'Bucket': "xxx",
    'Key': leKey
  }
  return s3.getObject(params).promise();
}

let thebase = await base64_encode('stuff');

Hope this helps

Related