Fail harder when *all* layers fail to load

This was actually being _triggered_ by the fact that the user outfits page doesn't generate great outfit image URLs! It doesn't encode the layerUrls parameter, so now that image URLs sometimes contain `&`, the parameter was being misparsed.

Example:
```
http://localhost:3000/api/outfitImage?size=300&layerUrls=https://impress-2020.openneo.net/api/assetImage?libraryUrl=https%3A%2F%2Fimages.neopets.com%2Fcp%2Fitems%2Fdata%2F000%2F000%2F054%2F54348_cf1cfe10c7%2Fall-background.js&size=300,http://images.neopets.com/cp/bio/data/000/000/041/41572_0450defb29/41572.svg,http://images.neopets.com/cp/bio/data/000/000/041/41570_83582a4a83/41570.svg,http://images.neopets.com/cp/bio/data/000/000/041/41571_7e6c072e12/41571.svg,http://images.neopets.com/cp/bio/data/000/000/041/41582_06159c1e4d/41582.svg,http://images.neopets.com/cp/bio/data/000/000/041/41574_520e661a8a/41574.svg,http://images.neopets.com/cp/bio/data/000/000/041/41573_f4f480ba37/41573.svg,https://impress-asset-images.openneo.net/object/000/000/480/480378/300x300.png?v2-1597211608000
```

would get the following list of layer URLs:
```
["https://impress-2020.openneo.net/api/assetImage?libraryUrl=https://images.neopets.com/cp/items/data/000/000/054/54348_cf1cfe10c7/all-background.js"]
```

Anyway, I'm gonna fix that (probably by just not using this layerUrls param anymore and moving to the new outfit ID + timestamp URLs), but let's also just have clearer error messages instead of just a blank image! That way, if something similar happens again, the client will fall back to alt text, instead of showing a blank image.
This commit is contained in:
Emi Matchu 2021-09-03 14:55:50 -07:00
parent 42628dffab
commit ae6b012f88

View file

@ -1,11 +1,18 @@
import { createCanvas, loadImage } from "canvas";
async function renderOutfitImage(layerRefs, size) {
async function renderOutfitImage(layerUrls, size) {
const canvas = createCanvas(size, size);
const ctx = canvas.getContext("2d");
const images = await Promise.all(layerRefs.map(loadImageAndSkipOnFailure));
const images = await Promise.all(layerUrls.map(loadImageAndSkipOnFailure));
const loadedImages = images.filter((image) => image);
if (loadedImages.length === 0) {
throw new Error(
`Could not load any of the layer images: ${layerUrls.join(", ")}`
);
}
for (const image of loadedImages) {
ctx.drawImage(image, 0, 0, size, size);
}
@ -13,7 +20,7 @@ async function renderOutfitImage(layerRefs, size) {
return {
image: canvas.toBuffer(),
status:
loadedImages.length === layerRefs.length ? "success" : "partial-failure",
loadedImages.length === layerUrls.length ? "success" : "partial-failure",
};
}