From 71d9b611e24ed91461fb833601dbc16a0a4b7d6a Mon Sep 17 00:00:00 2001 From: Shawn Li Date: Wed, 23 Sep 2020 17:44:03 +1000 Subject: [PATCH] Add json field (#31) * return only the first element of Records for S3 events * add json field, when publish message it will be stringified, then parsed back to json when consume the message * add limitation of maximum 256KB message so we can catch the error if json filed is too large --- index.d.ts | 2 ++ index.js | 57 ++++++++++++++++++++++++++++++++++++++++++++++++---- package.json | 2 +- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index f807c91..ca1c136 100644 --- a/index.d.ts +++ b/index.d.ts @@ -56,6 +56,8 @@ declare module "@luxuryescapes/lib-events" { const PROPERTY_UPDATE: string; const PROPERTY_DELETE: string; + const ROOM_AVAILABILITY_UPDATE: string; + const HOTEL_RESERVATION_SITEMINDER_ERROR: string; const HOTEL_RESERVATION_TRAVELCLICK_ERROR: string; diff --git a/index.js b/index.js index 644a84e..62e1dd7 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,9 @@ const sns = new AWS.SNS({ region: process.env.AWS_SNS_REGION }); +// Amazon SNS currently allows a maximum size of 256 KB for published messages. +const MAX_EVENT_MESSAGE_SIZE = 256 * 1024; + const typeList = [ "ORDER_PENDING", "ORDER_COMPLETED", @@ -98,7 +101,23 @@ class InvalidEventMessageError extends Error { } } -function dispatch({ type, uri, id, checksum, source, message }) { +class InvalidEventJsonError extends Error { + constructor(message, status) { + super(message); + this.name = this.constructor.name; + Error.captureStackTrace(this, this.constructor); + } +} + +class InvalidEventSizeError extends Error { + constructor(message, status) { + super(message); + this.name = this.constructor.name; + Error.captureStackTrace(this, this.constructor); + } +} + +function dispatch({ type, uri, id, checksum, source, message, json }) { if (!types[type]) { throw new InvalidEventTypeError(`invalid event type '${type}'`); } @@ -115,6 +134,13 @@ function dispatch({ type, uri, id, checksum, source, message }) { throw new InvalidEventMessageError("event message is required"); } + let jsonStr; + try { + jsonStr = JSON.stringify(json); + } catch (e) { + throw new InvalidEventJsonError("event json is invalid"); + } + const messageAttributes = { type: { DataType: "String", @@ -127,6 +153,10 @@ function dispatch({ type, uri, id, checksum, source, message }) { source: { DataType: "String", StringValue: source + }, + json: { + DataType: "String", + StringValue: jsonStr } }; @@ -150,6 +180,13 @@ function dispatch({ type, uri, id, checksum, source, message }) { Message: message }; + if ( + Buffer.byteLength(JSON.stringify(eventParams), "utf8") > + MAX_EVENT_MESSAGE_SIZE + ) { + throw new InvalidEventSizeError("json message exceeded limit of 256KB"); + } + if (process.env.IGNORE_EVENTS == "true") { return Promise.resolve(); } @@ -191,7 +228,9 @@ function deleteMessage(message) { function getAttributes(body) { const bodyJson = JSON.parse(body); // handle s3 upload event - if (bodyJson.Records) return bodyJson.Records; + // currently we can only one record per s3 event + // https://stackoverflow.com/questions/40765699/how-many-records-can-be-in-s3-put-event-lambda-trigger/40767563#40767563 + if (bodyJson.Records) return bodyJson.Records[0]; else if (bodyJson.MessageAttributes) { // handle sns message return mapAttributes(bodyJson); @@ -204,12 +243,22 @@ function getAttributes(body) { function mapAttributes(data) { const attributeReducer = (accumulator, currentValue) => { if (data.MessageAttributes[currentValue]) { - accumulator[currentValue] = data.MessageAttributes[currentValue].Value; + if (currentValue === "json") { + try { + accumulator[currentValue] = JSON.parse( + data.MessageAttributes[currentValue].Value + ); + } catch (e) { + throw new InvalidEventJsonError(`unable to parse json`); + } + } else { + accumulator[currentValue] = data.MessageAttributes[currentValue].Value; + } } return accumulator; }; - const attributeList = ["type", "uri", "id", "checksum"]; + const attributeList = ["type", "uri", "id", "checksum", "json"]; return attributeList.reduce(attributeReducer, {}); } diff --git a/package.json b/package.json index 504d1c7..740ebe2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@luxuryescapes/lib-events", - "version": "1.0.30", + "version": "1.0.31", "main": "index.js", "scripts": { "test": "./node_modules/.bin/jest && yarn run lint",