Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
akilavan-jayakumar committed Sep 8, 2023
0 parents commit 8b6e376
Show file tree
Hide file tree
Showing 18 changed files with 586 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Release Database Connector Service
on:
push:
tags:
- 'v*' # P

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Creating 'Release' Directory
run: mkdir -p release/functions
- name: Installing Packages for 'Image Processor' & Creating the Zip
run: cd functions/image_processor/ && npm install --omit=dev && zip -r ../../release/functions/image_processor.zip .
- name: Copying Project Template JSON
run: cp project-template-1.0.0.json release/project-template-1.0.0.json
- name: Creating Zip of Release Folder
run: cd release && zip -r release.zip .

# - uses: actions/checkout@v2
- uses: ncipollo/release-action@v1
with:
artifacts: './release/release.zip'
bodyFile: 'README.md'
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ env.RELEASE_VERSION }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.catalystrc
catalyst.json
**/node_modules
**/package-lock.json
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## Image Processor CodeLib Solution
The Image Processor CodeLib solution enables you to resize images to the required dimensions and compress them without distorting the image quality.

**Note:** You can get more detailed information on the steps to install and configure the Image Processor CodeLib solution from your Catalyst console. You must navigate to the bottom of your Catalyst console where you will find the ***Catalyst CodeLib*** section. You can click on the **Image Processor CodeLib** tile to access the steps.


### How does the CodeLib solution work?


Upon installing this CodeLib solution, pre-defined Catalyst components specific to the solution will be automatically configured in your project. This includes one [Catalyst Serverless function](https://docs.catalyst.zoho.com/en/serverless/help/functions/introduction/) ([Advanced I/O](https://docs.catalyst.zoho.com/en/serverless/help/functions/advanced-io/)) in **Node.js**. We will also be using the Catalyst SmartBrowz service in this CodeLib solution.



Upon the installation of the CodeLib solution, when you invoke the **/resize** endpoint of the **image_processor([Advanced I/O](https://docs.catalyst.zoho.com/en/serverless/help/functions/advanced-io/))** function as a *cURL* request, the image is resized and rendered as a 2-dimensional object with the height and width provided in the request payload, using the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext) and placed in an HTML file. Along with the dimensions, you must also configure the original image path to file in your local system, in the request payload. We will be using the Catalyst SmartBrowz service to connect to a headless Chrome and take a screenshot of the HTML page served in the browser containing the image. We have implemented this using the Puppeteer framework, a popular Node.js library that is used to control the headless browser using the pre-configured commands in Javascript. The screenshot will be provided as the response in the *.png* format.

You will also need to configure a key named **CODELIB\_SECRET\_KEY** as an [environmental variable ](https://docs.catalyst.zoho.com/en/serverless/help/functions/implementation/#environmental-variables)in the function's code, and pass this in the request header every time you invoke the endpoints of the pre-configured function in the CodeLib solutionThis key allows you to access the Catalyst resources of the CodeLib solution securely.

Similarly, when you invoke the **/compress** endpoint of the **image_processor([Advanced I/O](https://docs.catalyst.zoho.com/en/serverless/help/functions/advanced-io/))** function as a *cURL* request by configuring the original image file path and level of compression required, the image will be compressed based on the inputs provided in the request payload.

Similar to the **/resize** endpoint, we have again used the SmartBrowz's [PDF & Screenshot](https://docs.catalyst.zoho.com/en/smartbrowz/help/pdfnscreenshot/introduction/) component to take a screenshot and send its a response in the *.png* format. Also note that, the height and width dimensions of the input image should be 2000\*2000 pixels. If the dimensions are any less than the configured limit, we would automatically resize your image to 2000\*2000 pixels using the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext) and then compress the image based on the required compression level using the [**HTMLCanvasElement.toDataURL()**](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) method of the API.

**Note:** You can get more detailed information on the steps to install and configure the Image Processor CodeLib solution from the ***Catalyst CodeLib*** section in your Catalyst console.

### Resources Involved:

The following Catalyst resources are used as a part of the Image Processor CodeLib solution:

**1. [Catalyst Serverless Functions](https://docs.catalyst.zoho.com/en/serverless/help/functions/introduction/):**

This **image_processor([Advanced I/O](https://docs.catalyst.zoho.com/en/serverless/help/functions/advanced-io/)) function** handles the logic to resize and compress the input images, and returns the resized or compressed image as the response in the *.png* format.

**2. [Catalyst SmartBrowz](https://docs.catalyst.zoho.com/en/smartbrowz/getting-started/introduction/):**

We have used Catalyst SmartBrowz service in this CodeLib solution to connect to a headless Chrome browser. The images modified using the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext) will be in the HTML format. We will input this HTML file to the Puppeteer framework through the SmartBrowz service. This will serve the HTML in a browser webpage and take a screenshot of the updated image using the [PDF & Screenshot component](https://docs.catalyst.zoho.com/en/smartbrowz/help/pdfnscreenshot/introduction/), and return it in the .*png* format.
14 changes: 14 additions & 0 deletions functions/image_processor/catalyst-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"deployment": {
"name": "image_processor",
"stack": "node16",
"type": "advancedio",
"env_variables": {
"BROWSER_WS_ENDPOINT": "Your Catalyst SmartBrowz WS endpoint",
"CODELIB_SECRET_KEY": "CODELIB_FAKE_KEY"
}
},
"execution": {
"main": "index.js"
}
}
21 changes: 21 additions & 0 deletions functions/image_processor/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class AppConstants {
static NumberRegex = /^[0-9]+$/
static File = {
MaxSize: 5 * 1000 * 1000
}

static Headers = {
CodelibSecretKey: 'catalyst-codelib-secret-key'
}

static Env = {
CodelibSecretKey: 'CODELIB_SECRET_KEY',
BrowserWSEndpoint: 'BROWSER_WS_ENDPOINT'
}

static MountingDivID = 'root'
static MaxImageWidth = 2000
static MaxImageHeight = 2000
}

module.exports = AppConstants
11 changes: 11 additions & 0 deletions functions/image_processor/errors/AppError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class AppError extends Error {
statusCode = 500

constructor (statusCode, message) {
super()

this.statusCode = statusCode
this.message = message
}
}
module.exports = AppError
3 changes: 3 additions & 0 deletions functions/image_processor/errors/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const AppError = require('./AppError')

module.exports = { AppError }
26 changes: 26 additions & 0 deletions functions/image_processor/handlers/ErrorHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const { AppError } = require('../errors')

class ErrorHandler {
processError = (err) => {
if (err instanceof AppError) {
return {
status: 'failure',
statusCode: err.statusCode,
message: err.message
}
} else {
console.log('Error :::', err?.message || err)
return {
status: 'failure',
statusCode: 500,
message:
"We're unable to process your request. Kindly check logs to know more details."
}
}
}

static getInstance = () => {
return new ErrorHandler()
}
}
module.exports = ErrorHandler
90 changes: 90 additions & 0 deletions functions/image_processor/handlers/FileUploadHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const path = require('path')
const multer = require('multer')

const { AppError } = require('../errors')
const AppConstants = require('../constants')
const { FileService } = require('../services')

class FileUploadHandler {
#__fields = {}
#__request = null
#__response = null

constructor (request, response, fields) {
this.#__fields = fields
this.#__request = request
this.#__response = response
}

handleFileUpload = () => {
const storage = multer.diskStorage({
destination: FileService.getInstance().getTempDirectory(),
filename: function (__request, file, cb) {
cb(null, Date.now() + path.extname(file.originalname))
}
})
const upload = multer({
storage,
limits: {
fileSize: AppConstants.File.MaxSize
},
fileFilter: (__request, file, cb) => {
const fileName = path.parse(file.originalname).name
if (!['image/png', 'image/jpg', 'image/jpeg'].includes(file.mimetype)) {
cb(
new AppError(
400,
`${file.fieldname} must be a one of the following formats: jpg,jpeg or png file.`
)
)
} else if (!/^[A-Za-z0-9_-]*$/.test(fileName)) {
cb(
new AppError(
400,
'Invalid value for filename. Filename must contain only alphanumeric characters, underscores and hyphens'
)
)
} else {
cb(null, true)
}
}
}).fields(this.#__fields)

return new Promise((resolve, reject) => {
upload(this.#__request, this.#__response, (err) => {
if (err) {
if (err instanceof multer.MulterError) {
if (err.code === 'LIMIT_FILE_COUNT') {
reject(
new AppError(400, `${err.field} can contain a single file.`)
)
} else if (err.code === 'LIMIT_FILE_SIZE') {
reject(
new AppError(400, `${err.field} size should not exceed 5 MB.`)
)
} else if (err.code === 'LIMIT_UNEXPECTED_FILE') {
reject(
new AppError(
400,
'file must be named with one of the following values: ' +
this.#__fields.map((field) => field.name)
)
)
} else {
reject(err)
}
} else {
reject(err)
}
} else {
resolve('')
}
})
})
}

static getInstance = (request, response, fields) => {
return new FileUploadHandler(request, response, fields)
}
}
module.exports = FileUploadHandler
4 changes: 4 additions & 0 deletions functions/image_processor/handlers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const ErrorHandler = require('./ErrorHandler')
const FileUploadHandler = require('./FileUploadHandler')

module.exports = { FileUploadHandler, ErrorHandler }
Loading

0 comments on commit 8b6e376

Please sign in to comment.