Skip to content
This repository has been archived by the owner on Feb 23, 2022. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
wpscholar committed Oct 11, 2019
0 parents commit c4b9896
Show file tree
Hide file tree
Showing 9 changed files with 442 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
*.zip
12 changes: 12 additions & 0 deletions deploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const {execSync} = require('child_process');
const fs = require('fs');
const path = require('path');

const lambda = 'bluehost-screenshot-service';

if (fs.existsSync(`./${lambda}.zip`)) {
fs.unlinkSync(`${lambda}.zip`);
}

execSync(`zip -r ${lambda}.zip . -x "*.git*" -x "*.zip"`);
execSync(`aws lambda update-function-code --function-name '${lambda}' --zip-file fileb://${lambda}.zip --profile bluehost --region=us-west-2`);
196 changes: 196 additions & 0 deletions functions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
const {Lambda, S3} = require('aws-sdk');
const {get} = require('axios');
const crypto = require('crypto');
const {readFileSync} = require('fs');
const {Readable} = require('stream');

const lambda = new Lambda();
const s3 = new S3();

/**
* Take a file and convert to a base64 encoded string.
*
* @param buffer A Buffer instance.
* @returns {string} A base64 encoded string.
*/
function base64Encode(buffer) {
return new Buffer.from(buffer).toString('base64');
}

/**
* Take a base64 encoded string and convert to a buffer.
*
* @param {string} base64
* @returns {Buffer}
*/
function base64Decode(base64) {
return new Buffer.from(base64, 'base64');
}

/**
* Convert a buffer to a stream
*
* @param {Buffer} buffer
* @returns {Readable}
*/
function bufferToStream(buffer) {
return new Readable({
read() {
this.push(buffer);
this.push(null);
}
});
}

/**
* Get an MD5 hash of a string.
*
* @param {string} data
* @returns {string}
*/
function md5(data) {
return crypto.createHash('md5').update(data).digest('hex');
}

/**
* Upload a file to Amazon S3.
*
* @param {string} bucket
* @param {string} file
* @param {Readable} stream
*/
async function uploadToS3(bucket, file, stream) {
const params = {
Bucket: bucket,
Key: file,
Body: stream,
};

return await new Promise((resolve, reject) => {
s3.upload(params, (err, data) => err ? reject(err) : resolve(data));
});
}


/**
* Fetch a file from Amazon S3.
*
* @param {string} bucket
* @param {string} file
*/
async function fetchFromS3(bucket, file) {
const params = {
Bucket: bucket,
Key: file,
};

return await new Promise((resolve, reject) => {
s3.getObject(params, (err, data) => err ? reject(err) : resolve(data));
});
}

/**
* Check if a file exists on Amazon S3 (doesn't work with directories).
*
* @param {string} bucket The S3 bucket name.
* @param {string} file The file path on S3.
* @returns {boolean} Whether or not the file exists.
*/
async function fileExistsOnS3(bucket, file) {

const params = {
Bucket: bucket,
Key: file,
};

return await new Promise((resolve, reject) => {
s3.headObject(params, (err, data) => err ? reject(err) : resolve(data));
});
}

/**
* Get a screenshot given a URL.
*
* @param {string }url
* @returns {string}
*/
async function captureScreenshot(url) {
const params = {
FunctionName: 'bluehost-generate-screenshot',
Payload: JSON.stringify({url}, null, 2),
};

return await new Promise((resolve, reject) => {
lambda.invoke(params, (err, data) => err ? reject(err) : resolve(JSON.parse(data.Payload)));
});
}

/**
* Send an image as a response.
*
* @param base64
* @returns {{headers: {"Content-Type": string}, isBase64Encoded: boolean, body: string, statusCode: number}}
*/
function sendImage(base64) {
return {
statusCode: 200,
headers: {
'Content-Type': 'image/png',
},
body: `data:image/png;base64,${base64}`,
isBase64Encoded: true,
};
}

/**
* Send a placeholder image as a response.
*
* @returns {{headers: {"Content-Type": string}, isBase64Encoded: boolean, body: string, statusCode: number}}
*/
function sendPlaceholderImage() {
return sendImage(base64Encode(readFileSync('./placeholder.png')));
}

/**
* Send an error response.
*
* @param {string} message
* @returns {{headers: {}, isBase64Encoded: boolean, body: *, statusCode: number}}
*/
function sendError(message = 'Unable to generate screenshot') {
return {
statusCode: 500,
headers: {},
body: JSON.stringify({
status: 'error',
message,
}),
isBase64Encoded: false,
};
}

/**
* Send a 404 response.
*
* @returns {{statusCode: number}}
*/
function send404() {
return {
statusCode: 404,
};
}

module.exports = {
base64Decode,
base64Encode,
bufferToStream,
captureScreenshot,
fetchFromS3,
fileExistsOnS3,
md5,
send404,
sendError,
sendImage,
sendPlaceholderImage,
uploadToS3,
};
12 changes: 12 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const {sendError} = require('./functions');
const {Screenshot} = require('./screenshot');

exports.handler = async (event) => {
try {
const url = decodeURIComponent(event.queryStringParameters.url);
const screenshot = new Screenshot(url);
return await screenshot.fetch();
} catch (e) {
return sendError();
}
};
11 changes: 11 additions & 0 deletions local.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
var {handler} = require('./index');

process.env.S3_BUCKET = 'micah-remote';

handler({
queryStringParameters: {
url: 'https://wpscholar.com',
}
})
.then(response => console.log(response))
.catch(error => console.error(error));
137 changes: 137 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "bluehost-screenshot-service",
"version": "1.0.0",
"description": "A screenshot service provided by Bluehost",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Micah Wood <[email protected]>",
"license": "ISC",
"dependencies": {
"aws-sdk": "^2.547.0",
"axios": "^0.19.0"
}
}
Binary file added placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit c4b9896

Please sign in to comment.