-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhandler.js
126 lines (119 loc) · 3.73 KB
/
handler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
'use strict';
const AWS = require('aws-sdk');
const Jimp = require('jimp');
const hash = require('object-hash');
const s3 = new AWS.S3({
params: {
Bucket: process.env.S3_BUCKET,
},
});
module.exports.index = (event, context, callback) => {
function handleError(error) {
const response = {
statusCode: error.statusCode || 500,
body: JSON.stringify({
error: error.statusCode ? error : { message: error.message },
}),
};
callback(null, response);
}
const imgKey = event.pathParameters.img;
const originalKey = `originals/${imgKey}`;
const processedKey = `processed/${hash.MD5(event.queryStringParameters)}-${imgKey}`;
const originalPublicUrl = `https://s3.amazonaws.com/${process.env.S3_BUCKET}/originals/${imgKey}`;
const processedPublicUrl = `https://s3.amazonaws.com/${process.env.S3_BUCKET}/${processedKey}`;
// Check if an original object exists
s3.headObject({ Key: originalKey }).promise().then(() => {
// Check if we have the processed version already
s3.headObject({ Key: processedKey }).promise().then(() => {
const response = {
statusCode: 301,
headers: {
Location: processedPublicUrl,
'Cache-Control': 'public, max-age=31536000',
},
};
callback(null, response);
// Will throw an error if not found
}).catch(error => {
if (error.statusCode !== 404) {
return handleError(error);
}
// Download the original file
Jimp.read(originalPublicUrl).then(img => {
// JIMP options we are currently supporting
const options = [
'contain',
'cover',
'resize',
'scale',
'scaleToFit',
'autocrop',
'crop',
'flip',
'mirror',
'rotate',
'brightness',
'contrast',
'dither565',
'greyscale',
'invert',
'normalize',
'fade',
'opacity',
'opaque',
'background',
'gaussian',
'blur',
'posterize',
'sepia',
];
// Apply transforms to the img object
options.forEach(option => {
if (event.queryStringParameters[option]) {
const params = event.queryStringParameters[option].split(',').map(val => {
const num = Number(val);
if (Number.isFinite(num)) {
return num;
} else {
const normalizedName = val.toUpperCase();
if (Jimp[normalizedName]) {
return Jimp[normalizedName];
}
}
return val;
});
img[option].apply(img, params);
}
});
// Get the buffer data for the new image
img.getBuffer(img.getMIME(), (err, data) => {
if (err) {
handleError(err);
} else {
const putParams = {
Key: processedKey,
ACL: 'public-read',
Body: data,
ContentLength: data.length,
ContentType: img.getMIME(),
CacheControl: 'public, max-age=31536000',
};
// Upload new image data to S3
s3.putObject(putParams).promise().then(() => {
// Return a 301 (which should get cached by CloudFront)
const response = {
statusCode: 301,
headers: {
Location: processedPublicUrl,
'Cache-Control': 'public, max-age=31536000',
},
};
callback(null, response);
}).catch(handleError);
}
});
}).catch(handleError);
});
}).catch(handleError)
};