...
 
......@@ -78,61 +78,57 @@ module.exports = function (options, plugins) {
emailError
}
try {
if (ifModifiedSince) {
checkModifiedTime(function(modified) {
if (modified) {
doGet();
if (ifModifiedSince) {
checkModifiedTime(function(modified) {
if (modified) {
doGet();
} else {
res.sendStatus(304);
}
});
} else {
doGet();
}
function doGet() {
getRendition(function (renditionData, lastModifiedTime, error) {
if (renditionData) {
let contentType;
let contentLength;
let body;
if (renditionData instanceof Buffer) {
contentType = 'image/jpeg';
contentLength = renditionData.length;
body = renditionData;
} else {
res.sendStatus(304);
contentType = (renditionData.ContentType.startsWith('image') ? renditionData.ContentType : 'image/jpeg');
contentLength = renditionData.ContentLength;
body = renditionData.Body;
}
});
} else {
doGet();
}
function doGet() {
getRendition(function (renditionData, lastModifiedTime) {
if (renditionData) {
let contentType;
let contentLength;
let body;
if (renditionData instanceof Buffer) {
contentType = 'image/jpeg';
contentLength = renditionData.length;
body = renditionData;
} else {
contentType = (renditionData.ContentType.startsWith('image') ? renditionData.ContentType : 'image/jpeg');
contentLength = renditionData.ContentLength;
body = renditionData.Body;
}
if (lastModifiedTime) {
res.setHeader("last-modified", lastModifiedTime);
}
res.setHeader("cache-control", "max-age=31536000");
res.setHeader("content-type", contentType);
res.setHeader("content-length", contentLength);
res.send(body);
} else {
throw new Error("Missing rendition data");
if (lastModifiedTime) {
res.setHeader("last-modified", lastModifiedTime);
}
});
}
} catch (err) {
log.error("Problem generating image: ", err);
//res.status(500).send("<b>Problem generating image:</b> " + err);
res.status(302);
res.setHeader("Location", (usedOriginalFailover ? options.publicBaseUri : "") + slingImg);
res.send("Temporary image error: " + err);
if (emailError && isWorthEmailing()) {
emailError({
subject: "Blacklight img-opt error",
text: err,
req: req
});
}
res.setHeader("cache-control", "max-age=31536000");
res.setHeader("content-type", contentType);
res.setHeader("content-length", contentLength);
res.send(body);
} else {
log.error("Problem generating image: ", error);
//res.status(500).send("<b>Problem generating image:</b> " + err);
res.status(302);
res.setHeader("Location", (usedOriginalFailover ? options.publicBaseUri : "") + slingImg);
res.send("Temporary image error: " + error);
if (emailError && isWorthEmailing()) {
emailError({
subject: "Blacklight img-opt error",
text: err,
req: req
});
}
}
});
}
/********************************************************************************************/
......@@ -169,7 +165,10 @@ module.exports = function (options, plugins) {
function checkModifiedTime(cb) {
/* Get last modified date of original */
sc.get(slingImg + "/jcr:content", 0, function(err, data) {
if (!err && data && data._jcr_lastModified) {
if (err && err.response && err.response.status !== 404) {
// If we can't communicate with sling, assume rendition cache is good
originalMtime = renditionMtime;
} else if (!err && data && data._jcr_lastModified) {
originalMtime = Date.parse(data._jcr_lastModified);
}
......@@ -192,7 +191,8 @@ module.exports = function (options, plugins) {
let loadPerCPU = avg / cpuCount;
// console.log(`\nCPU Load: ${loadPerCPU}`, avg);
if (loadPerCPU > options.loadThresholdPerCPU) {
throw new Error(`CPU load average above threshold for image optimization: ${loadPerCPU}`);
cb(null, null, new Error(`CPU load average above threshold for image optimization: ${loadPerCPU}`));
return;
}
}
......@@ -204,7 +204,8 @@ module.exports = function (options, plugins) {
var cropping = parts.shift();
if (sizing && !sizing.match(/^[\d\^\%\!<\>x]*$/)) {
throw new Error("Bad sizing string: " + sizing);
cb(null, null, new Error("Bad sizing string: " + sizing));
return;
}
if (cropping) {
......@@ -214,15 +215,18 @@ module.exports = function (options, plugins) {
let rectangleCrop = /([\d\,]+(-|$)){4}/;
let sizeCrop = /\d+x\d+/;
if (cropping && (!cropping.match(rectangleCrop) && !cropping.match(sizeCrop))) {
throw new Error("Bad cropping string: " + cropping);
cb(null, null, new Error("Bad cropping string: " + cropping));
return;
}
if (isNaN(quality)) {
throw new Error("Bad quality string: " + quality);
cb(null, null, new Error("Bad quality string: " + quality));
return;
}
if (!extension.match(/jpe?g/i)) {
throw new Error("Optimizer currently only handles the JPG extension");
cb(null, null, new Error("Optimizer currently only handles the JPG extension"));
return;
}
......@@ -268,7 +272,10 @@ module.exports = function (options, plugins) {
checkTimes();
} else {
sc.get(slingImg + "/jcr:content", 0, function(err, data) {
if (!err && data && data._jcr_lastModified) {
if (err && err.response && err.response.status !== 404) {
// If we can't communicate with sling, assume rendition cache is good
originalMtime = renditionMtime;
} else if (data && data._jcr_lastModified) {
originalMtime = Date.parse(data._jcr_lastModified);
}
......@@ -281,7 +288,7 @@ module.exports = function (options, plugins) {
// Cannot get the original image to compare
if (processor) {
// No point in continuing
throw new Error("Cannot find original image");
cb(null, null, new Error("Cannot find original image"));
} else {
// Attempt to generate image anyways, probably via the failover
generateRendition();
......@@ -334,33 +341,37 @@ module.exports = function (options, plugins) {
imageOptions: imageOptions
};
try {
executeProcessor(payload, function (rendition) {
dealWithRendition(rendition);
});
} catch (error) {
// Fallback logic
if (!processor && options.publicBaseUri && !usedOriginalFailover) {
usedOriginalFailover = true;
log.warning("Reading sling image from failover: " + options.publicBaseUri + payload.originalPath);
const fallbackPayload = {
originalPath: payload.originalPath,
sling: {
environmentName: "fallback",
mode: "publish",
params: {
baseUri: options.publicBaseUri
executeProcessor(payload, function (rendition, error) {
if (rendition) {
dealWithRendition(rendition);
} else {
// Fallback logic
if (!processor && options.publicBaseUri && !usedOriginalFailover) {
usedOriginalFailover = true;
log.warning("Reading sling image from failover: " + options.publicBaseUri + payload.originalPath);
const fallbackPayload = {
originalPath: payload.originalPath,
sling: {
environmentName: "fallback",
mode: "publish",
params: {
baseUri: options.publicBaseUri
}
},
imageOptions: imageOptions
}
executeProcessor(fallbackPayload, function (rendition, error) {
if (rendition) {
dealWithRendition(rendition);
} else {
cb(null, null, error);
}
},
imageOptions: imageOptions
});
} else {
cb(null, null, error);
}
executeProcessor(fallbackPayload, function (rendition) {
dealWithRendition(rendition);
});
} else {
throw error;
}
}
});
}
function dealWithRendition(rendition) {
......@@ -385,8 +396,8 @@ module.exports = function (options, plugins) {
function executeProcessor(payload, cb) {
if (processor) {
// Execute processor
processor.processRendition(payload, function(renditionBuffer) {
cb(renditionBuffer);
processor.processRendition(payload, function(renditionBuffer, error) {
cb(renditionBuffer, error);
});
} else {
// Use local version of lambda script
......@@ -395,16 +406,18 @@ module.exports = function (options, plugins) {
const status = data.status;
const rendition = data.rendition;
if (error) {
throw new Error(`Img-opt execution error: Status: ${status} Error: ${error}`)
cb(null, new Error(`Img-opt execution error: Status: ${status} Error: ${error}`));
} else if (status === 200 && rendition) {
if (rendition.type === "Buffer") {
cb(Buffer.from(rendition));
} else {
throw new Error(`Invalid img-opt response type: ${rendition.type} Status: ${status}`)
cb(null, new Error(`Invalid img-opt response type: ${rendition.type} Status: ${status}`));
}
} else {
throw new Error(`Img-opt execution error: Status ${status}`);
cb(null, new Error(`Img-opt execution error: Status ${status}`));
}
}).catch((error) => {
cb(null, error);
});
}
}
......